Skip to content

Commit a94b93a

Browse files
authored
Merge pull request #4 from fazo96/improvements
Many improvements
2 parents 613cfea + 9514006 commit a94b93a

30 files changed

Lines changed: 3452 additions & 211 deletions

.eslintrc.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"parserOptions": {
5+
"ecmaVersion": 2022,
6+
"sourceType": "module"
7+
},
8+
"plugins": [
9+
"@typescript-eslint"
10+
],
11+
"extends": [
12+
"eslint:recommended",
13+
"plugin:@typescript-eslint/eslint-recommended",
14+
"plugin:@typescript-eslint/recommended"
15+
],
16+
"rules": {
17+
"no-unused-vars": "off",
18+
"@typescript-eslint/no-unused-vars": [
19+
"error",
20+
{
21+
"args": "none"
22+
}
23+
],
24+
"@typescript-eslint/ban-ts-comment": "off",
25+
"no-prototype-builtins": "off",
26+
"@typescript-eslint/no-empty-function": "off"
27+
}
28+
}

.github/workflows/test.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: ['main', 'develop']
6+
pull_request:
7+
branches: ['main', 'develop']
8+
9+
jobs:
10+
test:
11+
name: Run tests
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout repository
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '20'
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Run tests
27+
run: npx vitest run
28+
29+
- name: Run linting
30+
run: npm run lint

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ Thumbs.db
2424
.hotreload
2525
data.json
2626
node_modules/
27-
src/
27+
28+
# Test coverage
29+
coverage/

AGENTS.md

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# Solo TTRPG Notation Plugin - Developer Guide
2+
3+
This guide provides essential information for agentic coding agents working on this Obsidian plugin.
4+
5+
## Agent Workflow
6+
7+
**IMPORTANT:** After making ANY change to the codebase, you MUST:
8+
9+
1. **Run tests**: `nix-shell -p nodejs_20 --run "npm run test"`
10+
2. **Run linting**: `nix-shell -p nodejs_20 --run "npm run lint"`
11+
12+
Both tests and linting MUST pass before your changes are complete.
13+
14+
### When to Update Tests
15+
16+
You MUST update/add tests when:
17+
- **Fixing a bug** - Add a test that reproduces the bug and verifies the fix
18+
- **Adding a new feature** - Add tests covering the new functionality
19+
- **Changing how something works** - Update existing tests to match new behavior
20+
- **Refactoring** - Ensure tests still pass and cover the refactored code
21+
22+
### Test Coverage Requirements
23+
24+
- All parser logic should be unit tested
25+
- All indexer logic should be unit tested
26+
- Use the mock Obsidian API in `tests/__mocks__/obsidian.ts` to avoid file I/O
27+
- Use fixtures in `tests/fixtures/` for integration-style tests
28+
29+
## Build & Development Commands
30+
31+
```bash
32+
npm run dev # Development build with watch mode (rebuilds on file changes)
33+
npm run build # Production build to main.js
34+
npm run lint # Lint TypeScript files
35+
npm run lint:fix # Auto-fix linting issues
36+
npm run test # Run unit tests (fast parallel execution)
37+
npm run test:watch # Run tests in watch mode for development
38+
npm run test:ui # Run tests with UI interface
39+
npm run test:coverage # Run tests with coverage report
40+
```
41+
42+
## Testing
43+
44+
The project uses **Vitest** for fast, parallel unit testing.
45+
46+
### Test Structure
47+
48+
```
49+
tests/
50+
├── __mocks__/ # Mock implementations of dependencies
51+
│ └── obsidian.ts # Mock Obsidian API
52+
├── setup/ # Test setup and utilities
53+
│ ├── obsidian-mock.ts # Mock classes for testing
54+
│ └── vitest-setup.ts # Global test setup
55+
├── parser/ # Parser unit tests
56+
│ ├── CodeBlockParser.test.ts
57+
│ └── TagExtractor.test.ts
58+
├── indexer/ # Indexer unit tests
59+
└── fixtures/ # Test data files
60+
└── synthetic-campaign.md # Minimal test campaign
61+
```
62+
63+
### Running Tests
64+
65+
- Unit tests execute in parallel by default (4 workers)
66+
- Tests mock the Obsidian API to avoid requiring a real Obsidian instance
67+
- Fixtures directory contains synthetic campaign data for integration testing
68+
69+
### Important Notes
70+
71+
- Tests use parallel execution for speed (configured in vitest.config.ts)
72+
- All parser and indexer logic can be unit tested without file I/O
73+
- Manual testing in Obsidian still required for UI integration and edge cases
74+
75+
## Project Structure
76+
77+
```
78+
src/
79+
├── main.ts # Plugin entry point
80+
├── settings.ts # Settings interface & tab
81+
├── types/notation.ts # All TypeScript type definitions
82+
├── parser/ # Parsers for different notation elements
83+
├── indexer/ # Campaign file indexing & caching
84+
├── views/ # Obsidian ItemView implementations
85+
├── templates/ # Template management & snippets
86+
├── commands/ # Command registration
87+
└── utils/ # Helper functions
88+
```
89+
90+
## Code Style Guidelines
91+
92+
### TypeScript Configuration
93+
- Target: ES2022
94+
- Strict mode enabled (noImplicitAny, strictNullChecks)
95+
- Path alias: `@/*``src/*`
96+
97+
### Naming Conventions
98+
- Classes: PascalCase (`NotationParser`, `DashboardView`)
99+
- Methods/Functions: camelCase (`parseCampaignFile`, `render`)
100+
- Constants: UPPER_SNAKE_CASE (`VIEW_TYPE_DASHBOARD`)
101+
- Private members: TypeScript `private` keyword (no underscore prefix)
102+
- File names: PascalCase for types, camelCase for implementations
103+
104+
### Import Style
105+
```typescript
106+
// External dependencies first
107+
import { Plugin, App, Notice } from 'obsidian';
108+
109+
// Internal types
110+
import { Campaign, Session, Location } from '../types/notation';
111+
112+
// Same directory imports use './'
113+
import { CodeBlockParser } from './CodeBlockParser';
114+
115+
// Relative imports with '../' for parent directories
116+
import { TemplateManager } from '../templates/TemplateManager';
117+
```
118+
119+
### Formatting
120+
- Use tabs for indentation (not spaces)
121+
- Single blank line between methods/functions
122+
- No trailing whitespace
123+
- Max line length: not enforced, but aim for readability
124+
125+
### JSDoc Comments
126+
Required for all public methods:
127+
```typescript
128+
/**
129+
* Parse a complete campaign file
130+
* @param content - The file content as string
131+
* @param filePath - Path to the campaign file
132+
* @returns Parsed Campaign object
133+
*/
134+
parseCampaignFile(content: string, filePath: string): Campaign {
135+
```
136+
137+
### Type Definitions
138+
All types defined in `src/types/notation.ts`. Use type guards for union types:
139+
```typescript
140+
export function isAction(element: NotationElement): element is Action {
141+
return element.type === 'action';
142+
}
143+
```
144+
145+
### Error Handling
146+
```typescript
147+
try {
148+
await this.templateManager.fillTemplate(template, variables);
149+
} catch (error) {
150+
console.error('Error message:', error);
151+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
152+
new Notice(`User-friendly message: ${errorMsg}`);
153+
}
154+
```
155+
156+
### Obsidian Plugin Patterns
157+
158+
#### Commands
159+
```typescript
160+
plugin.addCommand({
161+
id: 'command-id',
162+
name: 'Command Name',
163+
checkCallback: (checking: boolean) => {
164+
// Check if command should be available
165+
return true;
166+
},
167+
editorCallback: (editor: Editor, view: MarkdownView) => {
168+
// Editor context
169+
},
170+
callback: () => {
171+
// General context
172+
}
173+
});
174+
```
175+
176+
#### Views
177+
All views extend `ItemView` and implement:
178+
- `getViewType()`: Unique string identifier
179+
- `getDisplayText()`: Display name in UI
180+
- `getIcon()`: Obsidian icon name
181+
- `onOpen()`: Called when view opens
182+
- `onClose()`: Cleanup resources
183+
184+
#### Settings
185+
Settings defined in `src/settings.ts` with:
186+
- Interface definition
187+
- `DEFAULT_SETTINGS` constant
188+
- `SoloRPGSettingTab` class extending `PluginSettingTab`
189+
190+
### Parsing Architecture
191+
- `NotationParser` orchestrates parsing
192+
- Sub-parsers handle specific elements (CodeBlockParser, TagExtractor, ProgressParser)
193+
- Parsers return typed objects from `src/types/notation.ts`
194+
- Use regex for markdown notation patterns
195+
196+
### Indexing
197+
- `NotationIndexer` manages campaign data
198+
- Indexes entire vault or single files
199+
- Caches parsed data with expiry (configurable)
200+
- Listens to file change events
201+
202+
### UI Construction
203+
Use Obsidian's DOM methods:
204+
```typescript
205+
const container = this.containerEl.children[1];
206+
container.empty();
207+
container.addClass('solo-rpg-container');
208+
209+
const header = container.createDiv({ cls: 'solo-rpg-header' });
210+
header.createEl('h2', { text: 'Title' });
211+
```
212+
213+
## Important Notes
214+
215+
- **No tests exist** - All changes require manual testing in Obsidian
216+
- Build output is `main.js` (CommonJS format via esbuild)
217+
- Obsidian API types imported from `obsidian` package
218+
- Plugin entry point is `src/main.ts``export default class SoloRPGNotationPlugin extends Plugin`
219+
- All notation parsing happens inside code blocks (```) in markdown files
220+
- Italian locale support exists (Session/Sessione headers)
221+
222+
## Common Patterns
223+
224+
### Creating a new view:
225+
1. Extend `ItemView` in `src/views/`
226+
2. Define unique `VIEW_TYPE_*` constant
227+
3. Register view in `main.ts` via `registerView()`
228+
4. Add ribbon icon or command to open view
229+
230+
### Adding new notation elements:
231+
1. Add type to `NotationElement` union in `types/notation.ts`
232+
2. Create parser in `parser/` or extend existing parser
233+
3. Add to indexing logic in `NotationParser.collectAllTags()`
234+
4. Add type guard function
235+
236+
### Adding settings:
237+
1. Update `SoloRPGSettings` interface
238+
2. Update `DEFAULT_SETTINGS` constant
239+
3. Add UI in `SoloRPGSettingTab.display()`

CONTRIBUTING.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
This project requires Node.js 20 or higher.
2+
3+
**Note for AI-Assisted Development**: This repository includes `AGENTS.md`, which contains specific instructions for AI coding agents working on this codebase. If you're using an AI assistant or automated agent, make sure it is [compatible with AGENTS.md](https://agents.md).
4+
5+
## Prerequisites
6+
7+
- Node.js 20 or higher
8+
- npm or yarn
9+
10+
## Development Workflow
11+
12+
Once you have Node.js installed, you can contribute to this project:
13+
14+
1. **Fork and clone** this repository
15+
2. **Install dependencies**: `npm install`
16+
3. **Make your changes** to the source code
17+
4. **Build locally**: `npm run build`
18+
5. **Test in Obsidian** by copying the built files to your vault's plugins folder
19+
20+
## Testing
21+
22+
Before submitting a pull request, ensure:
23+
24+
- All tests pass: `npm run test`
25+
- All linting checks pass: `npm run lint`
26+
- Your code follows the project's style guidelines
27+
28+
### Running Tests
29+
30+
```bash
31+
npm test # Run all tests
32+
npm run test:watch # Watch mode for development
33+
npm run test:ui # Interactive test UI
34+
npm run test:coverage # Run tests with coverage report
35+
```
36+
37+
### Running Linting
38+
39+
```bash
40+
npm run lint # Check for linting errors
41+
npm run lint:fix # Auto-fix linting issues
42+
```
43+
44+
**All tests and linting must pass before your PR can be merged.**
45+
46+
## Project Guidelines
47+
48+
- Follow existing code style and patterns
49+
- Add tests for new features or bug fixes
50+
- Update documentation when changing functionality
51+
- Keep commits focused and well-described

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ Click the dice icon (🎲) in the left sidebar to open the Campaign Dashboard, o
148148
#### Player Characters
149149
```
150150
[PC:Name] - Simple PC mention
151-
[PC:Name|HP:12|Armor:3] - PC with current stats
151+
[PC:Name|warrior|hero] - PC with tags
152+
[PC:Name|HP:12|Armor:3] - PC with stat-like tags
153+
[PC:Name|warrior|HP:12] - PC with mixed tags
152154
```
153155

154156
### Random Generation
@@ -329,7 +331,7 @@ Open **Settings → Solo TTRPG Notation** to configure:
329331
## Support
330332

331333
- **Issues & Bugs**: [GitHub Issues](https://github.com/roberto-b/solorpgnotation/issues)
332-
- **Notation Spec**: See `solo_notation.md` for complete specification
334+
- **Notation Spec**: See [Solo TTRPG Notation](https://zeruhur.itch.io/solo-ttrpg-notation)
333335
- **Examples**: Check the `examples/` folder for sample campaigns
334336

335337
## Credits

0 commit comments

Comments
 (0)