jamdesk 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +42 -0
  2. package/dist/__tests__/unit/docs-json-writer.test.js +59 -1
  3. package/dist/__tests__/unit/docs-json-writer.test.js.map +1 -1
  4. package/dist/__tests__/unit/spellcheck-fix.test.d.ts +2 -0
  5. package/dist/__tests__/unit/spellcheck-fix.test.d.ts.map +1 -0
  6. package/dist/__tests__/unit/spellcheck-fix.test.js +82 -0
  7. package/dist/__tests__/unit/spellcheck-fix.test.js.map +1 -0
  8. package/dist/__tests__/unit/spellcheck-utils.test.d.ts +2 -0
  9. package/dist/__tests__/unit/spellcheck-utils.test.d.ts.map +1 -0
  10. package/dist/__tests__/unit/spellcheck-utils.test.js +234 -0
  11. package/dist/__tests__/unit/spellcheck-utils.test.js.map +1 -0
  12. package/dist/__tests__/unit/tech-words.test.d.ts +2 -0
  13. package/dist/__tests__/unit/tech-words.test.d.ts.map +1 -0
  14. package/dist/__tests__/unit/tech-words.test.js +31 -0
  15. package/dist/__tests__/unit/tech-words.test.js.map +1 -0
  16. package/dist/commands/spellcheck.d.ts +13 -0
  17. package/dist/commands/spellcheck.d.ts.map +1 -0
  18. package/dist/commands/spellcheck.js +144 -0
  19. package/dist/commands/spellcheck.js.map +1 -0
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +28 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/deps.js +3 -3
  24. package/dist/lib/deps.js.map +1 -1
  25. package/dist/lib/docs-json-writer.d.ts +6 -0
  26. package/dist/lib/docs-json-writer.d.ts.map +1 -1
  27. package/dist/lib/docs-json-writer.js +29 -0
  28. package/dist/lib/docs-json-writer.js.map +1 -1
  29. package/dist/lib/spellcheck-fix.d.ts +37 -0
  30. package/dist/lib/spellcheck-fix.d.ts.map +1 -0
  31. package/dist/lib/spellcheck-fix.js +292 -0
  32. package/dist/lib/spellcheck-fix.js.map +1 -0
  33. package/dist/lib/spellcheck-utils.d.ts +36 -0
  34. package/dist/lib/spellcheck-utils.d.ts.map +1 -0
  35. package/dist/lib/spellcheck-utils.js +138 -0
  36. package/dist/lib/spellcheck-utils.js.map +1 -0
  37. package/dist/lib/tech-words.d.ts +9 -0
  38. package/dist/lib/tech-words.d.ts.map +1 -0
  39. package/dist/lib/tech-words.js +118 -0
  40. package/dist/lib/tech-words.js.map +1 -0
  41. package/package.json +3 -1
  42. package/vendored/app/[[...slug]]/page.tsx +2 -2
  43. package/vendored/app/layout.tsx +3 -6
  44. package/vendored/components/navigation/SocialFooter.tsx +10 -5
  45. package/vendored/hooks/useShikiHighlight.ts +1 -11
  46. package/vendored/lib/docs-types.ts +12 -3
  47. package/vendored/lib/docs.ts +80 -2
  48. package/vendored/lib/isr-build-executor.ts +10 -0
  49. package/vendored/lib/middleware-helpers.ts +10 -3
  50. package/vendored/lib/shiki-client.ts +64 -15
  51. package/vendored/lib/static-artifacts.ts +82 -3
  52. package/vendored/lib/static-file-route.ts +5 -5
  53. package/vendored/schema/docs-schema.json +18 -0
  54. package/vendored/scripts/dev-project.cjs +3 -10
  55. package/vendored/scripts/enhance-navigation.cjs +16 -28
  56. package/vendored/themes/base.css +0 -2
package/README.md CHANGED
@@ -98,6 +98,8 @@ npx jamdesk dev
98
98
  | `jamdesk validate` | Validate docs.json, MDX syntax, OpenAPI specs |
99
99
  | `jamdesk openapi-check <spec>` | Validate a single OpenAPI spec |
100
100
  | `jamdesk broken-links` | Find broken internal links |
101
+ | `jamdesk spellcheck` | Check for spelling errors |
102
+ | `jamdesk spellcheck --fix` | Interactively fix or ignore misspellings |
101
103
  | `jamdesk rename <from> <to>` | Rename file, update all references |
102
104
  | `jamdesk deploy-proxy cloudflare` | Deploy Cloudflare Worker for subpath hosting |
103
105
  | `jamdesk doctor` | Diagnose environment issues |
@@ -204,6 +206,46 @@ docs/getting-started.mdx:15 - /docs/quikstart
204
206
  Found 1 broken link in 45 files.
205
207
  ```
206
208
 
209
+ ### `jamdesk spellcheck`
210
+
211
+ Check your docs for spelling errors:
212
+
213
+ ```bash
214
+ jamdesk spellcheck
215
+ ```
216
+
217
+ ```
218
+ getting-started.mdx:14 - "recieve"
219
+ └─ Did you mean: receive
220
+
221
+ Found 3 misspellings across 24 pages.
222
+ Tip: Run "jamdesk spellcheck --fix" to interactively fix or ignore words.
223
+ ```
224
+
225
+ Uses an English dictionary with 150+ built-in tech terms (API, GraphQL, Kubernetes, etc.) so common jargon doesn't flag. Add project-specific words to `docs.json`:
226
+
227
+ ```json
228
+ {
229
+ "spellcheck": {
230
+ "ignore": ["YourProduct", "kubectl"]
231
+ }
232
+ }
233
+ ```
234
+
235
+ | Option | Description |
236
+ |--------|-------------|
237
+ | `--fix` | Interactively fix misspellings or add to ignore list |
238
+ | `--json` | Output as JSON (for CI) |
239
+ | `--verbose` | Show each file as it's checked |
240
+
241
+ **`--fix` mode** steps through each unique misspelled word and lets you choose:
242
+
243
+ - **Fix →** replace with a suggestion across all files. Up to 3 suggestions shown, best match marked as recommended
244
+ - **Ignore** — add to `spellcheck.ignore` in docs.json so it won't flag again
245
+ - **Skip** — do nothing for this run
246
+
247
+ Changes are previewed and confirmed before applying. Prose-safe: won't modify words inside code blocks, inline code, or JSX attributes. Your project name from docs.json is automatically ignored.
248
+
207
249
  ## File Management
208
250
 
209
251
  Rename a page and every reference updates automatically — docs.json navigation, internal links, snippet imports:
@@ -3,7 +3,7 @@ import fs from 'fs-extra';
3
3
  import path from 'path';
4
4
  import os from 'os';
5
5
  import JSON5 from 'json5';
6
- import { writeProjectIdToDocsJson } from '../../lib/docs-json-writer.js';
6
+ import { writeProjectIdToDocsJson, writeIgnoreWordsToDocsJson } from '../../lib/docs-json-writer.js';
7
7
  describe('writeProjectIdToDocsJson', () => {
8
8
  let tmpDir;
9
9
  let filePath;
@@ -68,4 +68,62 @@ describe('writeProjectIdToDocsJson', () => {
68
68
  await expect(writeProjectIdToDocsJson(filePath, 'proj id')).rejects.toThrow('Invalid projectId');
69
69
  });
70
70
  });
71
+ describe('writeIgnoreWordsToDocsJson', () => {
72
+ let tmpDir;
73
+ let filePath;
74
+ beforeEach(async () => {
75
+ tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'jd-test-'));
76
+ filePath = path.join(tmpDir, 'docs.json');
77
+ });
78
+ afterEach(async () => {
79
+ await fs.remove(tmpDir);
80
+ });
81
+ async function writeAndRead(initial, words) {
82
+ await fs.writeFile(filePath, initial);
83
+ await writeIgnoreWordsToDocsJson(filePath, words);
84
+ return fs.readFile(filePath, 'utf-8');
85
+ }
86
+ it('creates spellcheck.ignore when no spellcheck field exists', async () => {
87
+ const content = await writeAndRead('{\n "name": "Test"\n}', ['kubectl', 'Acme']);
88
+ const parsed = JSON.parse(content);
89
+ expect(parsed.spellcheck).toEqual({ ignore: ['acme', 'kubectl'] });
90
+ });
91
+ it('appends to existing spellcheck.ignore array', async () => {
92
+ const content = await writeAndRead('{\n "name": "Test",\n "spellcheck": {\n "ignore": ["existing"]\n }\n}', ['newword']);
93
+ const parsed = JSON.parse(content);
94
+ expect(parsed.spellcheck.ignore).toEqual(['existing', 'newword']);
95
+ });
96
+ it('sorts words alphabetically and lowercases them', async () => {
97
+ const content = await writeAndRead('{\n "name": "Test"\n}', ['Zebra', 'apple', 'Mango']);
98
+ const parsed = JSON.parse(content);
99
+ expect(parsed.spellcheck.ignore).toEqual(['apple', 'mango', 'zebra']);
100
+ });
101
+ it('deduplicates against existing words', async () => {
102
+ const content = await writeAndRead('{\n "name": "Test",\n "spellcheck": {\n "ignore": ["existing"]\n }\n}', ['existing', 'newword']);
103
+ const parsed = JSON.parse(content);
104
+ expect(parsed.spellcheck.ignore).toEqual(['existing', 'newword']);
105
+ });
106
+ it('preserves existing indentation', async () => {
107
+ const content = await writeAndRead('{\n "name": "Test"\n}', ['word']);
108
+ expect(content).toContain(' "spellcheck"');
109
+ });
110
+ it('preserves other fields in docs.json', async () => {
111
+ const content = await writeAndRead('{\n "name": "Test",\n "theme": "jam",\n "navigation": {}\n}', ['word']);
112
+ const parsed = JSON.parse(content);
113
+ expect(parsed.name).toBe('Test');
114
+ expect(parsed.theme).toBe('jam');
115
+ expect(parsed.navigation).toEqual({});
116
+ expect(parsed.spellcheck.ignore).toEqual(['word']);
117
+ });
118
+ it('handles empty ignore array', async () => {
119
+ const content = await writeAndRead('{\n "name": "Test",\n "spellcheck": {\n "ignore": []\n }\n}', ['word']);
120
+ const parsed = JSON.parse(content);
121
+ expect(parsed.spellcheck.ignore).toEqual(['word']);
122
+ });
123
+ it('does nothing when words array is empty', async () => {
124
+ const initial = '{\n "name": "Test"\n}';
125
+ const content = await writeAndRead(initial, []);
126
+ expect(content).toBe(initial);
127
+ });
128
+ });
71
129
  //# sourceMappingURL=docs-json-writer.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-json-writer.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/docs-json-writer.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"docs-json-writer.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/docs-json-writer.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spellcheck-fix.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck-fix.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/spellcheck-fix.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { replaceWordInLine, applyFixesToContent, escapeRegex } from '../../lib/spellcheck-fix.js';
6
+ describe('escapeRegex', () => {
7
+ it('escapes special regex characters', () => {
8
+ expect(escapeRegex('hello.world')).toBe('hello\\.world');
9
+ expect(escapeRegex('test[0]')).toBe('test\\[0\\]');
10
+ expect(escapeRegex('a+b*c')).toBe('a\\+b\\*c');
11
+ });
12
+ it('passes through normal strings', () => {
13
+ expect(escapeRegex('hello')).toBe('hello');
14
+ });
15
+ });
16
+ describe('replaceWordInLine', () => {
17
+ it('replaces word in plain prose', () => {
18
+ expect(replaceWordInLine('This is a recieve test', 'recieve', 'receive'))
19
+ .toBe('This is a receive test');
20
+ });
21
+ it('respects word boundaries', () => {
22
+ expect(replaceWordInLine('the other therapy', 'the', 'a'))
23
+ .toBe('a other therapy');
24
+ });
25
+ it('skips word inside inline code', () => {
26
+ expect(replaceWordInLine('Run `recieve` and recieve data', 'recieve', 'receive'))
27
+ .toBe('Run `recieve` and receive data');
28
+ });
29
+ it('skips word inside JSX attribute values', () => {
30
+ expect(replaceWordInLine('<Note title="recieve">recieve this</Note>', 'recieve', 'receive'))
31
+ .toBe('<Note title="recieve">receive this</Note>');
32
+ });
33
+ it('preserves first-letter capitalization', () => {
34
+ expect(replaceWordInLine('Recieve the data', 'Recieve', 'receive'))
35
+ .toBe('Receive the data');
36
+ });
37
+ it('preserves ALL_CAPS', () => {
38
+ expect(replaceWordInLine('RECIEVE THE DATA', 'RECIEVE', 'receive'))
39
+ .toBe('RECEIVE THE DATA');
40
+ });
41
+ it('replaces multiple prose occurrences on one line', () => {
42
+ expect(replaceWordInLine('recieve and recieve again', 'recieve', 'receive'))
43
+ .toBe('receive and receive again');
44
+ });
45
+ it('returns line unchanged if word not found', () => {
46
+ expect(replaceWordInLine('no match here', 'recieve', 'receive'))
47
+ .toBe('no match here');
48
+ });
49
+ it('skips word inside JSX expression attributes', () => {
50
+ expect(replaceWordInLine('prop={recieve} and recieve', 'recieve', 'receive'))
51
+ .toBe('prop={recieve} and receive');
52
+ });
53
+ });
54
+ describe('applyFixesToContent', () => {
55
+ it('replaces word across all lines', () => {
56
+ const content = 'Line one recieve\nLine two\nLine three recieve';
57
+ const result = applyFixesToContent(content, [{ word: 'recieve', replacement: 'receive' }]);
58
+ expect(result).toBe('Line one receive\nLine two\nLine three receive');
59
+ });
60
+ it('applies multiple fixes', () => {
61
+ const content = 'recieve the teh data';
62
+ const result = applyFixesToContent(content, [
63
+ { word: 'recieve', replacement: 'receive' },
64
+ { word: 'teh', replacement: 'the' },
65
+ ]);
66
+ expect(result).toBe('receive the the data');
67
+ });
68
+ it('preserves inline code during multi-fix', () => {
69
+ const content = 'Use `recieve` but also recieve and teh';
70
+ const result = applyFixesToContent(content, [
71
+ { word: 'recieve', replacement: 'receive' },
72
+ { word: 'teh', replacement: 'the' },
73
+ ]);
74
+ expect(result).toBe('Use `recieve` but also receive and the');
75
+ });
76
+ it('returns content unchanged when no matches', () => {
77
+ const content = 'All correct here';
78
+ const result = applyFixesToContent(content, [{ word: 'recieve', replacement: 'receive' }]);
79
+ expect(result).toBe('All correct here');
80
+ });
81
+ });
82
+ //# sourceMappingURL=spellcheck-fix.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck-fix.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/spellcheck-fix.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=spellcheck-utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck-utils.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/spellcheck-utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,234 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { extractProseWords, createSpellchecker, buildIgnoreWords } from '../../lib/spellcheck-utils.js';
6
+ describe('createSpellchecker', () => {
7
+ it('loads dictionary and checks correct words', () => {
8
+ const spell = createSpellchecker([]);
9
+ expect(spell.correct('hello')).toBe(true);
10
+ expect(spell.correct('world')).toBe(true);
11
+ });
12
+ it('flags misspelled words', () => {
13
+ const spell = createSpellchecker([]);
14
+ expect(spell.correct('recieve')).toBe(false);
15
+ expect(spell.correct('authetication')).toBe(false);
16
+ });
17
+ it('suggests corrections', () => {
18
+ const spell = createSpellchecker([]);
19
+ const suggestions = spell.suggest('recieve');
20
+ expect(suggestions).toContain('receive');
21
+ });
22
+ it('respects ignore words via add()', () => {
23
+ const spell = createSpellchecker(['Jamdesk', 'kubectl']);
24
+ expect(spell.correct('Jamdesk')).toBe(true);
25
+ expect(spell.correct('kubectl')).toBe(true);
26
+ });
27
+ });
28
+ describe('extractProseWords', () => {
29
+ it('extracts plain text words with line numbers', () => {
30
+ const content = 'Hello world\nThis is a test';
31
+ const words = extractProseWords(content);
32
+ expect(words).toContainEqual({ word: 'Hello', line: 1 });
33
+ expect(words).toContainEqual({ word: 'world', line: 1 });
34
+ expect(words).toContainEqual({ word: 'test', line: 2 });
35
+ });
36
+ it('skips frontmatter', () => {
37
+ const content = '---\ntitle: Some Mispeled Title\n---\nHello world';
38
+ const words = extractProseWords(content);
39
+ const wordTexts = words.map((w) => w.word);
40
+ expect(wordTexts).not.toContain('Mispeled');
41
+ expect(wordTexts).toContain('Hello');
42
+ });
43
+ it('skips fenced code blocks', () => {
44
+ const content = 'Before code\n```javascript\nconst misspeled = true;\n```\nAfter code';
45
+ const words = extractProseWords(content);
46
+ const wordTexts = words.map((w) => w.word);
47
+ expect(wordTexts).not.toContain('misspeled');
48
+ expect(wordTexts).toContain('Before');
49
+ expect(wordTexts).toContain('After');
50
+ });
51
+ it('skips inline code', () => {
52
+ const content = 'Run `misspeled` command here';
53
+ const words = extractProseWords(content);
54
+ const wordTexts = words.map((w) => w.word);
55
+ expect(wordTexts).not.toContain('misspeled');
56
+ expect(wordTexts).toContain('Run');
57
+ expect(wordTexts).toContain('command');
58
+ });
59
+ it('skips import/export statements', () => {
60
+ const content = 'import { misspeled } from "module"\nexport default misspeled\nHello world';
61
+ const words = extractProseWords(content);
62
+ const wordTexts = words.map((w) => w.word);
63
+ expect(wordTexts).not.toContain('misspeled');
64
+ expect(wordTexts).toContain('Hello');
65
+ });
66
+ it('strips JSX tags but keeps inner text', () => {
67
+ const content = '<Note title="ignored">Check this content</Note>';
68
+ const words = extractProseWords(content);
69
+ const wordTexts = words.map((w) => w.word);
70
+ expect(wordTexts).toContain('Check');
71
+ expect(wordTexts).toContain('content');
72
+ expect(wordTexts).not.toContain('title');
73
+ expect(wordTexts).not.toContain('ignored');
74
+ expect(wordTexts).not.toContain('Note');
75
+ });
76
+ it('keeps markdown link text, strips URL', () => {
77
+ const content = 'Click [this link](https://example.com/page) here';
78
+ const words = extractProseWords(content);
79
+ const wordTexts = words.map((w) => w.word);
80
+ expect(wordTexts).toContain('Click');
81
+ expect(wordTexts).toContain('this');
82
+ expect(wordTexts).toContain('link');
83
+ expect(wordTexts).toContain('here');
84
+ expect(wordTexts).not.toContain('https');
85
+ expect(wordTexts).not.toContain('example');
86
+ });
87
+ it('strips standalone URLs', () => {
88
+ const content = 'Visit https://example.com/path for details';
89
+ const words = extractProseWords(content);
90
+ const wordTexts = words.map((w) => w.word);
91
+ expect(wordTexts).not.toContain('https');
92
+ expect(wordTexts).not.toContain('example');
93
+ expect(wordTexts).toContain('Visit');
94
+ expect(wordTexts).toContain('details');
95
+ });
96
+ it('strips HTML entities', () => {
97
+ const content = 'Use &lt; and &amp; operators';
98
+ const words = extractProseWords(content);
99
+ const wordTexts = words.map((w) => w.word);
100
+ expect(wordTexts).not.toContain('lt');
101
+ expect(wordTexts).not.toContain('amp');
102
+ expect(wordTexts).toContain('Use');
103
+ expect(wordTexts).toContain('operators');
104
+ });
105
+ it('strips MDX expressions', () => {
106
+ const content = 'Hello {variable} world {/* comment */} end';
107
+ const words = extractProseWords(content);
108
+ const wordTexts = words.map((w) => w.word);
109
+ expect(wordTexts).not.toContain('variable');
110
+ expect(wordTexts).not.toContain('comment');
111
+ expect(wordTexts).toContain('Hello');
112
+ expect(wordTexts).toContain('world');
113
+ });
114
+ it('skips camelCase and PascalCase tokens', () => {
115
+ const content = 'Use the onClick handler and MyComponent class';
116
+ const words = extractProseWords(content);
117
+ const wordTexts = words.map((w) => w.word);
118
+ expect(wordTexts).not.toContain('onClick');
119
+ expect(wordTexts).not.toContain('MyComponent');
120
+ expect(wordTexts).toContain('Use');
121
+ expect(wordTexts).toContain('handler');
122
+ });
123
+ it('skips ALL_CAPS tokens with underscores (constants)', () => {
124
+ const content = 'Set the API_KEY and MAX_RETRIES variable';
125
+ const words = extractProseWords(content);
126
+ const wordTexts = words.map((w) => w.word);
127
+ expect(wordTexts).not.toContain('API_KEY');
128
+ expect(wordTexts).not.toContain('MAX_RETRIES');
129
+ expect(wordTexts).toContain('Set');
130
+ expect(wordTexts).toContain('variable');
131
+ });
132
+ it('allows pure ALL_CAPS words through (handled by dictionary/tech list)', () => {
133
+ const content = 'Use HTTP and CONFIGURATON';
134
+ const words = extractProseWords(content);
135
+ const wordTexts = words.map((w) => w.word);
136
+ expect(wordTexts).toContain('HTTP');
137
+ expect(wordTexts).toContain('CONFIGURATON');
138
+ });
139
+ it('skips tokens with digits', () => {
140
+ const content = 'Use v2 or Node18 version';
141
+ const words = extractProseWords(content);
142
+ const wordTexts = words.map((w) => w.word);
143
+ expect(wordTexts).not.toContain('v2');
144
+ expect(wordTexts).not.toContain('Node18');
145
+ expect(wordTexts).toContain('Use');
146
+ expect(wordTexts).toContain('version');
147
+ });
148
+ it('handles possessives', () => {
149
+ const content = "Jamdesk's features are great";
150
+ const words = extractProseWords(content);
151
+ const wordTexts = words.map((w) => w.word);
152
+ expect(wordTexts).toContain('Jamdesk');
153
+ expect(wordTexts).not.toContain("Jamdesk's");
154
+ expect(wordTexts).toContain('features');
155
+ });
156
+ it('strips surrounding punctuation', () => {
157
+ const content = 'Hello, world! (great) "stuff"';
158
+ const words = extractProseWords(content);
159
+ const wordTexts = words.map((w) => w.word);
160
+ expect(wordTexts).toContain('Hello');
161
+ expect(wordTexts).toContain('world');
162
+ expect(wordTexts).toContain('great');
163
+ expect(wordTexts).toContain('stuff');
164
+ });
165
+ it('preserves correct line numbers after stripping', () => {
166
+ const content = '---\ntitle: Test\n---\n\nFirst line\n\nThird line';
167
+ const words = extractProseWords(content);
168
+ const first = words.find((w) => w.word === 'First');
169
+ const third = words.find((w) => w.word === 'Third');
170
+ expect(first?.line).toBe(5);
171
+ expect(third?.line).toBe(7);
172
+ });
173
+ it('skips self-closing JSX tags', () => {
174
+ const content = 'Before <Image src="/pic.png" alt="test" /> after';
175
+ const words = extractProseWords(content);
176
+ const wordTexts = words.map((w) => w.word);
177
+ expect(wordTexts).toContain('Before');
178
+ expect(wordTexts).toContain('after');
179
+ expect(wordTexts).not.toContain('Image');
180
+ expect(wordTexts).not.toContain('src');
181
+ expect(wordTexts).not.toContain('pic');
182
+ });
183
+ it('handles markdown headings', () => {
184
+ const content = '## Getting Started\n### Instalation Guide';
185
+ const words = extractProseWords(content);
186
+ const wordTexts = words.map((w) => w.word);
187
+ expect(wordTexts).toContain('Getting');
188
+ expect(wordTexts).toContain('Started');
189
+ expect(wordTexts).toContain('Instalation');
190
+ expect(wordTexts).not.toContain('##');
191
+ });
192
+ it('handles markdown images', () => {
193
+ const content = 'See ![screenshot of dashboard](images/dashboard.png) below';
194
+ const words = extractProseWords(content);
195
+ const wordTexts = words.map((w) => w.word);
196
+ expect(wordTexts).toContain('See');
197
+ expect(wordTexts).toContain('below');
198
+ expect(wordTexts).toContain('screenshot');
199
+ expect(wordTexts).not.toContain('images');
200
+ expect(wordTexts).not.toContain('png');
201
+ });
202
+ it('handles file paths', () => {
203
+ const content = 'Edit the /path/to/file.ts config';
204
+ const words = extractProseWords(content);
205
+ const wordTexts = words.map((w) => w.word);
206
+ expect(wordTexts).not.toContain('path');
207
+ expect(wordTexts).not.toContain('file');
208
+ expect(wordTexts).toContain('Edit');
209
+ expect(wordTexts).toContain('config');
210
+ });
211
+ });
212
+ describe('buildIgnoreWords', () => {
213
+ it('merges tech words and user words', () => {
214
+ const result = buildIgnoreWords(['API', 'SDK'], undefined, ['Acme']);
215
+ expect(result).toContain('API');
216
+ expect(result).toContain('SDK');
217
+ expect(result).toContain('Acme');
218
+ });
219
+ it('extracts individual words from project name', () => {
220
+ const result = buildIgnoreWords([], 'Acme Cloud Platform', []);
221
+ expect(result).toContain('Acme');
222
+ expect(result).toContain('Cloud');
223
+ expect(result).toContain('Platform');
224
+ });
225
+ it('handles undefined project name', () => {
226
+ const result = buildIgnoreWords(['API'], undefined, ['custom']);
227
+ expect(result).toEqual(['API', 'custom']);
228
+ });
229
+ it('handles empty inputs', () => {
230
+ const result = buildIgnoreWords([], undefined, []);
231
+ expect(result).toEqual([]);
232
+ });
233
+ });
234
+ //# sourceMappingURL=spellcheck-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck-utils.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/spellcheck-utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tech-words.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tech-words.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/unit/tech-words.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { TECH_WORDS } from '../../lib/tech-words.js';
6
+ describe('TECH_WORDS', () => {
7
+ it('is a non-empty array of strings', () => {
8
+ expect(Array.isArray(TECH_WORDS)).toBe(true);
9
+ expect(TECH_WORDS.length).toBeGreaterThan(50);
10
+ for (const word of TECH_WORDS) {
11
+ expect(typeof word).toBe('string');
12
+ expect(word.length).toBeGreaterThan(0);
13
+ }
14
+ });
15
+ it('contains common tech terms', () => {
16
+ const words = new Set(TECH_WORDS.map((w) => w.toLowerCase()));
17
+ expect(words.has('api')).toBe(true);
18
+ expect(words.has('sdk')).toBe(true);
19
+ expect(words.has('json')).toBe(true);
20
+ expect(words.has('graphql')).toBe(true);
21
+ expect(words.has('typescript')).toBe(true);
22
+ expect(words.has('webhook')).toBe(true);
23
+ expect(words.has('jamdesk')).toBe(true);
24
+ });
25
+ it('has no duplicates', () => {
26
+ const lower = TECH_WORDS.map((w) => w.toLowerCase());
27
+ const unique = new Set(lower);
28
+ expect(unique.size).toBe(lower.length);
29
+ });
30
+ });
31
+ //# sourceMappingURL=tech-words.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tech-words.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/tech-words.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC9C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Spellcheck Command
3
+ *
4
+ * Checks MDX documentation for spelling errors using nspell.
5
+ * Follows the same patterns as broken-links.ts.
6
+ */
7
+ export interface SpellcheckOptions {
8
+ verbose: boolean;
9
+ json?: boolean;
10
+ fix?: boolean;
11
+ }
12
+ export declare function spellcheck(options: SpellcheckOptions): Promise<void>;
13
+ //# sourceMappingURL=spellcheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck.d.ts","sourceRoot":"","sources":["../../src/commands/spellcheck.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuJ1E"}