jamdesk 1.1.6 → 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 (41) 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/docs-json-writer.d.ts +6 -0
  24. package/dist/lib/docs-json-writer.d.ts.map +1 -1
  25. package/dist/lib/docs-json-writer.js +29 -0
  26. package/dist/lib/docs-json-writer.js.map +1 -1
  27. package/dist/lib/spellcheck-fix.d.ts +37 -0
  28. package/dist/lib/spellcheck-fix.d.ts.map +1 -0
  29. package/dist/lib/spellcheck-fix.js +292 -0
  30. package/dist/lib/spellcheck-fix.js.map +1 -0
  31. package/dist/lib/spellcheck-utils.d.ts +36 -0
  32. package/dist/lib/spellcheck-utils.d.ts.map +1 -0
  33. package/dist/lib/spellcheck-utils.js +138 -0
  34. package/dist/lib/spellcheck-utils.js.map +1 -0
  35. package/dist/lib/tech-words.d.ts +9 -0
  36. package/dist/lib/tech-words.d.ts.map +1 -0
  37. package/dist/lib/tech-words.js +118 -0
  38. package/dist/lib/tech-words.js.map +1 -0
  39. package/package.json +3 -1
  40. package/vendored/lib/static-file-route.ts +1 -1
  41. package/vendored/schema/docs-schema.json +18 -0
@@ -0,0 +1,144 @@
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
+ import fs from 'fs-extra';
8
+ import path from 'path';
9
+ import { output } from '../lib/output.js';
10
+ import { spinner } from '../lib/spinner.js';
11
+ import { loadDocsConfig } from '../lib/docs-config.js';
12
+ import { extractAllPages } from '../lib/mdx-validator.js';
13
+ import { TECH_WORDS } from '../lib/tech-words.js';
14
+ import { extractProseWords, createSpellchecker, buildIgnoreWords, } from '../lib/spellcheck-utils.js';
15
+ export async function spellcheck(options) {
16
+ const { verbose, json, fix } = options;
17
+ if (fix && json) {
18
+ output.error('Cannot use --fix with --json');
19
+ output.hint('Use --fix for interactive mode or --json for CI output, not both');
20
+ process.exit(1);
21
+ }
22
+ const projectDir = process.cwd();
23
+ // Load docs.json
24
+ const config = await loadDocsConfig('docs.json');
25
+ if (!config) {
26
+ output.error('Could not load docs.json');
27
+ process.exit(1);
28
+ }
29
+ const pagePaths = extractAllPages(config.navigation);
30
+ if (verbose && !json) {
31
+ console.log(`Found ${pagePaths.length} pages to check`);
32
+ }
33
+ const spin = !json ? spinner('Checking spelling...') : null;
34
+ // Build ignore words from all sources
35
+ const configAny = config;
36
+ const spellcheckConfig = configAny.spellcheck;
37
+ const userIgnoreWords = spellcheckConfig?.ignore ?? [];
38
+ const projectName = configAny.name;
39
+ const ignoreWords = buildIgnoreWords(TECH_WORDS, projectName, userIgnoreWords);
40
+ const spell = createSpellchecker(ignoreWords);
41
+ // Phase 1: Find all misspellings
42
+ // Cache correct() results globally — a word checked in file 1 doesn't need
43
+ // rechecking in file 2. This is critical for large projects (3000+ pages).
44
+ const allMisspellings = [];
45
+ const correctCache = new Map();
46
+ let pagesChecked = 0;
47
+ for (const pagePath of pagePaths) {
48
+ const mdxPath = path.join(projectDir, `${pagePath}.mdx`);
49
+ const mdPath = path.join(projectDir, `${pagePath}.md`);
50
+ let filePath = null;
51
+ if (await fs.pathExists(mdxPath)) {
52
+ filePath = mdxPath;
53
+ }
54
+ else if (await fs.pathExists(mdPath)) {
55
+ filePath = mdPath;
56
+ }
57
+ if (!filePath)
58
+ continue;
59
+ pagesChecked++;
60
+ const content = await fs.readFile(filePath, 'utf8');
61
+ const relPath = path.relative(projectDir, filePath);
62
+ if (verbose && !json) {
63
+ spin?.stop();
64
+ console.log(` Checking ${relPath}...`);
65
+ spin?.start();
66
+ }
67
+ const words = extractProseWords(content);
68
+ const seenInFile = new Set();
69
+ for (const { word, line } of words) {
70
+ const key = word.toLowerCase();
71
+ if (seenInFile.has(key))
72
+ continue;
73
+ seenInFile.add(key);
74
+ // Check global cache first
75
+ let isCorrect = correctCache.get(key);
76
+ if (isCorrect === undefined) {
77
+ isCorrect = spell.correct(word);
78
+ correctCache.set(key, isCorrect);
79
+ }
80
+ if (!isCorrect) {
81
+ allMisspellings.push({ file: relPath, line, word, suggestions: [] });
82
+ }
83
+ }
84
+ }
85
+ // Phase 2: Compute suggestions for unique misspelled words
86
+ // suggest() is expensive (~20ms per word), so deduplicate across files and
87
+ // cap at 100 unique words. Beyond that, the project needs a spellcheck.ignore
88
+ // list rather than individual suggestions.
89
+ const MAX_SUGGESTIONS = 200;
90
+ const uniqueWords = new Set(allMisspellings.map((m) => m.word.toLowerCase()));
91
+ if (allMisspellings.length > 0) {
92
+ const suggestionCache = new Map();
93
+ if (uniqueWords.size <= MAX_SUGGESTIONS) {
94
+ if (spin) {
95
+ spin.text = `Computing suggestions for ${uniqueWords.size} unique misspellings...`;
96
+ }
97
+ for (const m of allMisspellings) {
98
+ const key = m.word.toLowerCase();
99
+ if (!suggestionCache.has(key)) {
100
+ suggestionCache.set(key, spell.suggest(m.word).slice(0, 3));
101
+ }
102
+ m.suggestions = suggestionCache.get(key);
103
+ }
104
+ }
105
+ else if (spin) {
106
+ spin.text = `Found ${uniqueWords.size} unique misspellings (skipping suggestions for speed)`;
107
+ }
108
+ }
109
+ spin?.stop();
110
+ // Interactive fix mode
111
+ if (fix && allMisspellings.length > 0) {
112
+ const { runInteractiveFix } = await import('../lib/spellcheck-fix.js');
113
+ const docsJsonPath = path.join(projectDir, 'docs.json');
114
+ await runInteractiveFix(allMisspellings, docsJsonPath, projectDir, spell);
115
+ process.exitCode = 0;
116
+ return;
117
+ }
118
+ // Report results — use process.exitCode instead of process.exit() to allow
119
+ // stdout to flush (process.exit() truncates piped output beyond 64KB)
120
+ if (json) {
121
+ console.log(JSON.stringify(allMisspellings, null, 2));
122
+ process.exitCode = allMisspellings.length > 0 ? 1 : 0;
123
+ return;
124
+ }
125
+ if (allMisspellings.length === 0) {
126
+ output.success(`No spelling errors found (checked ${pagesChecked} pages)`);
127
+ return;
128
+ }
129
+ console.log('\nMisspellings found:\n');
130
+ for (const { file, line, word, suggestions } of allMisspellings) {
131
+ console.log(`${file}:${line} - "${word}"`);
132
+ if (suggestions.length > 0) {
133
+ console.log(` └─ Did you mean: ${suggestions.join(', ')}`);
134
+ }
135
+ }
136
+ console.log(`\nFound ${allMisspellings.length} misspelling${allMisspellings.length === 1 ? '' : 's'} across ${pagesChecked} pages.`);
137
+ const uniqueCount = new Set(allMisspellings.map((m) => m.word.toLowerCase())).size;
138
+ console.log('Tip: Run "jamdesk spellcheck --fix" to interactively fix or ignore words.');
139
+ if (uniqueCount > MAX_SUGGESTIONS) {
140
+ console.log(` Suggestions were skipped (${uniqueCount} unique words). Add domain terms to your ignore list first.`);
141
+ }
142
+ process.exitCode = 1;
143
+ }
144
+ //# sourceMappingURL=spellcheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck.js","sourceRoot":"","sources":["../../src/commands/spellcheck.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Jamdesk CLI
4
4
  *
5
5
  * The user-facing CLI for local documentation development.
6
- * Commands: init, dev, validate, broken-links, rename, doctor, clean, update, migrate
6
+ * Commands: init, dev, validate, broken-links, spellcheck, rename, doctor, clean, update, migrate
7
7
  */
8
8
  export {};
9
9
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Jamdesk CLI
4
4
  *
5
5
  * The user-facing CLI for local documentation development.
6
- * Commands: init, dev, validate, broken-links, rename, doctor, clean, update, migrate
6
+ * Commands: init, dev, validate, broken-links, spellcheck, rename, doctor, clean, update, migrate
7
7
  */
8
8
  import { Command } from 'commander';
9
9
  import { checkForUpdates } from './lib/version.js';
@@ -169,6 +169,33 @@ Output shows the file, line number, and suggests corrections:
169
169
  const { brokenLinks } = await import('./commands/broken-links.js');
170
170
  await brokenLinks({ verbose });
171
171
  });
172
+ // Spellcheck command
173
+ program
174
+ .command('spellcheck')
175
+ .description('Check for spelling errors in documentation')
176
+ .option('--json', 'Output results as JSON')
177
+ .option('--fix', 'Interactive mode: fix misspellings or add to ignore list')
178
+ .addHelpText('after', `
179
+ Examples:
180
+ $ jamdesk spellcheck Check all pages
181
+ $ jamdesk spellcheck -v Show each file as it's checked
182
+ $ jamdesk spellcheck --json Output as JSON (for CI)
183
+ $ jamdesk spellcheck --fix Interactive fix/ignore mode
184
+
185
+ Checks prose content for spelling errors, skipping:
186
+ • Code blocks and inline code
187
+ • Frontmatter, imports, JSX
188
+ • URLs and file paths
189
+ • Common tech terms (API, SDK, TypeScript, etc.)
190
+
191
+ Add project-specific words to docs.json:
192
+ { "spellcheck": { "ignore": ["YourProduct", "kubectl"] } }
193
+ `)
194
+ .action(async (opts) => {
195
+ const verbose = program.opts().verbose;
196
+ const { spellcheck } = await import('./commands/spellcheck.js');
197
+ await spellcheck({ verbose, json: opts.json, fix: opts.fix });
198
+ });
172
199
  // Rename command
173
200
  program
174
201
  .command('rename <from> <to>')
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,8 @@
1
1
  export declare function writeProjectIdToDocsJson(docsJsonPath: string, projectId: string): Promise<void>;
2
+ /**
3
+ * Add words to the spellcheck.ignore array in docs.json.
4
+ * Uses JSON.parse/stringify with indent detection to safely handle arrays.
5
+ * Words are lowercased, sorted, and deduplicated.
6
+ */
7
+ export declare function writeIgnoreWordsToDocsJson(docsJsonPath: string, words: string[]): Promise<void>;
2
8
  //# sourceMappingURL=docs-json-writer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-json-writer.d.ts","sourceRoot":"","sources":["../../src/lib/docs-json-writer.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,CAC5C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
1
+ {"version":3,"file":"docs-json-writer.d.ts","sourceRoot":"","sources":["../../src/lib/docs-json-writer.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,CAC5C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAwCf;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
@@ -32,4 +32,33 @@ export async function writeProjectIdToDocsJson(docsJsonPath, projectId) {
32
32
  content = content.slice(0, insertPos) + insertion + content.slice(insertPos);
33
33
  await fs.writeFile(docsJsonPath, content);
34
34
  }
35
+ /**
36
+ * Add words to the spellcheck.ignore array in docs.json.
37
+ * Uses JSON.parse/stringify with indent detection to safely handle arrays.
38
+ * Words are lowercased, sorted, and deduplicated.
39
+ */
40
+ export async function writeIgnoreWordsToDocsJson(docsJsonPath, words) {
41
+ if (words.length === 0)
42
+ return;
43
+ const content = await fs.readFile(docsJsonPath, 'utf-8');
44
+ // Detect indentation from file
45
+ const indentMatch = content.match(/\{\s*\n(\s+)/);
46
+ const indent = indentMatch ? indentMatch[1] : ' ';
47
+ const indentSize = indent.length;
48
+ const config = JSON.parse(content);
49
+ // Ensure spellcheck.ignore exists
50
+ if (!config.spellcheck) {
51
+ config.spellcheck = { ignore: [] };
52
+ }
53
+ if (!config.spellcheck.ignore) {
54
+ config.spellcheck.ignore = [];
55
+ }
56
+ // Merge: lowercase new words, combine with existing, deduplicate, sort
57
+ const existing = new Set(config.spellcheck.ignore.map((w) => w.toLowerCase()));
58
+ for (const word of words) {
59
+ existing.add(word.toLowerCase());
60
+ }
61
+ config.spellcheck.ignore = [...existing].sort();
62
+ await fs.writeFile(docsJsonPath, JSON.stringify(config, null, indentSize) + '\n');
63
+ }
35
64
  //# sourceMappingURL=docs-json-writer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-json-writer.js","sourceRoot":"","sources":["../../src/lib/docs-json-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,YAAoB,EACpB,SAAiB;IAEjB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEvD,IAAI,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,6BAA6B,EAC7B,MAAM,SAAS,GAAG,CACnB,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnD,kFAAkF;IAClF,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3E,IAAI,SAAiB,CAAC;IACtB,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,sCAAsC;QACtC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC7D,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7D,CAAC;QACD,yEAAyE;QACzE,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjF,SAAS,GAAG,aAAa,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,MAAM,iBAAiB,SAAS,IAAI,CAAC;IAC5D,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAE7E,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"docs-json-writer.js","sourceRoot":"","sources":["../../src/lib/docs-json-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,YAAoB,EACpB,SAAiB;IAEjB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEvD,IAAI,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,OAAO,GAAG,OAAO,CAAC,OAAO,CACvB,6BAA6B,EAC7B,MAAM,SAAS,GAAG,CACnB,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnD,kFAAkF;IAClF,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3E,IAAI,SAAiB,CAAC;IACtB,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,sCAAsC;QACtC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC7D,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7D,CAAC;QACD,yEAAyE;QACzE,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjF,SAAS,GAAG,aAAa,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,MAAM,iBAAiB,SAAS,IAAI,CAAC;IAC5D,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAE7E,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,YAAoB,EACpB,KAAe;IAEf,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE/B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEzD,+BAA+B;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEnC,kCAAkC;IAClC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,CAAC,UAAU,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,CAAC;IAChC,CAAC;IAED,uEAAuE;IACvE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACvF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAEhD,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Spellcheck Fix Utilities
3
+ *
4
+ * Prose-safe word replacement and interactive fix flow for spellcheck --fix.
5
+ */
6
+ import type { Misspelling } from './spellcheck-utils.js';
7
+ export interface FixAction {
8
+ word: string;
9
+ replacement: string;
10
+ }
11
+ export interface FixDecision {
12
+ action: 'fix' | 'ignore' | 'skip';
13
+ word: string;
14
+ replacement?: string;
15
+ }
16
+ /** Escape special regex characters in a string. */
17
+ export declare function escapeRegex(str: string): string;
18
+ /**
19
+ * Replace a word in a single line, only within prose segments.
20
+ * Skips inline code, JSX attribute values, and URLs.
21
+ * Optionally accepts pre-computed non-prose ranges to avoid recomputation.
22
+ */
23
+ export declare function replaceWordInLine(line: string, word: string, replacement: string, nonProseRanges?: Array<[number, number]>): string;
24
+ /**
25
+ * Apply multiple word fixes to file content.
26
+ * Processes line-by-line, replacing only in prose segments.
27
+ */
28
+ export declare function applyFixesToContent(content: string, fixes: FixAction[]): string;
29
+ /**
30
+ * Run the interactive fix flow.
31
+ * Steps through each unique misspelled word and collects fix/ignore/skip decisions.
32
+ * Applies all changes after user confirmation.
33
+ */
34
+ export declare function runInteractiveFix(misspellings: Misspelling[], docsJsonPath: string, projectDir: string, spell?: {
35
+ suggest(word: string): string[];
36
+ }): Promise<void>;
37
+ //# sourceMappingURL=spellcheck-fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spellcheck-fix.d.ts","sourceRoot":"","sources":["../../src/lib/spellcheck-fix.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAMD,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAoBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,CAsCR;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,EAAE,GACjB,MAAM,CAgCR;AAqCD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,WAAW,EAAE,EAC3B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE;IAAE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAC1C,OAAO,CAAC,IAAI,CAAC,CA8Kf"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Spellcheck Fix Utilities
3
+ *
4
+ * Prose-safe word replacement and interactive fix flow for spellcheck --fix.
5
+ */
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import { select, confirm } from '@inquirer/prompts';
9
+ import { output } from './output.js';
10
+ import { writeIgnoreWordsToDocsJson } from './docs-json-writer.js';
11
+ /** Escape special regex characters in a string. */
12
+ export function escapeRegex(str) {
13
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
14
+ }
15
+ /** Build non-prose character ranges for a line (inline code, JSX attrs, URLs). */
16
+ function buildNonProseRanges(line) {
17
+ const ranges = [];
18
+ const patterns = [
19
+ /`[^`]*`/g, // Inline code
20
+ /[a-zA-Z]+=["'][^"']*["']/g, // JSX string attributes
21
+ /[a-zA-Z]+=\{[^}]*\}/g, // JSX expression attributes
22
+ /https?:\/\/[^\s)>\]]+/g, // URLs
23
+ /\]\([^)]*\)/g, // Markdown link/image URLs
24
+ ];
25
+ for (const pattern of patterns) {
26
+ for (const m of line.matchAll(pattern)) {
27
+ ranges.push([m.index, m.index + m[0].length]);
28
+ }
29
+ }
30
+ return ranges;
31
+ }
32
+ /**
33
+ * Replace a word in a single line, only within prose segments.
34
+ * Skips inline code, JSX attribute values, and URLs.
35
+ * Optionally accepts pre-computed non-prose ranges to avoid recomputation.
36
+ */
37
+ export function replaceWordInLine(line, word, replacement, nonProseRanges) {
38
+ const ranges = nonProseRanges ?? buildNonProseRanges(line);
39
+ function isInNonProse(pos) {
40
+ return ranges.some(([start, end]) => pos >= start && pos < end);
41
+ }
42
+ function caseAwareReplace(original, suggestion) {
43
+ if (!suggestion)
44
+ return suggestion;
45
+ if (original === original.toUpperCase() && original.length > 1) {
46
+ return suggestion.toUpperCase();
47
+ }
48
+ if (original[0] === original[0].toUpperCase()) {
49
+ return suggestion[0].toUpperCase() + suggestion.slice(1);
50
+ }
51
+ return suggestion;
52
+ }
53
+ const pattern = new RegExp(`\\b${escapeRegex(word)}\\b`, 'gi');
54
+ let result = '';
55
+ let lastIndex = 0;
56
+ for (const match of line.matchAll(pattern)) {
57
+ const matchStart = match.index;
58
+ const matchEnd = matchStart + match[0].length;
59
+ result += line.slice(lastIndex, matchStart);
60
+ if (isInNonProse(matchStart)) {
61
+ result += match[0];
62
+ }
63
+ else {
64
+ result += caseAwareReplace(match[0], replacement);
65
+ }
66
+ lastIndex = matchEnd;
67
+ }
68
+ result += line.slice(lastIndex);
69
+ return result;
70
+ }
71
+ /**
72
+ * Apply multiple word fixes to file content.
73
+ * Processes line-by-line, replacing only in prose segments.
74
+ */
75
+ export function applyFixesToContent(content, fixes) {
76
+ const lines = content.split('\n');
77
+ // Skip frontmatter (same logic as extractProseWords)
78
+ let startLine = 0;
79
+ if (lines[0]?.trim() === '---') {
80
+ for (let j = 1; j < lines.length; j++) {
81
+ if (lines[j].trim() === '---') {
82
+ startLine = j + 1;
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ for (let i = startLine; i < lines.length; i++) {
88
+ // Skip fenced code blocks
89
+ if (lines[i].trim().startsWith('```')) {
90
+ i++;
91
+ while (i < lines.length && !lines[i].trim().startsWith('```'))
92
+ i++;
93
+ continue;
94
+ }
95
+ // Skip import/export statements (matches extractProseWords behavior)
96
+ if (/^(import|export)\s/.test(lines[i].trim()))
97
+ continue;
98
+ for (const { word, replacement } of fixes) {
99
+ // Recompute ranges per fix since previous replacements may shift positions
100
+ lines[i] = replaceWordInLine(lines[i], word, replacement);
101
+ }
102
+ }
103
+ return lines.join('\n');
104
+ }
105
+ /**
106
+ * Group misspellings by unique word (lowercase key).
107
+ */
108
+ function groupMisspellings(misspellings) {
109
+ const groups = new Map();
110
+ for (const m of misspellings) {
111
+ const key = m.word.toLowerCase();
112
+ if (!groups.has(key)) {
113
+ groups.set(key, { casings: new Map(), files: [], suggestions: m.suggestions });
114
+ }
115
+ const g = groups.get(key);
116
+ g.casings.set(m.word, (g.casings.get(m.word) || 0) + 1);
117
+ g.files.push({ file: m.file, line: m.line });
118
+ }
119
+ return [...groups.entries()].map(([key, g]) => {
120
+ let bestWord = key;
121
+ let bestCount = 0;
122
+ for (const [w, c] of g.casings) {
123
+ if (c > bestCount) {
124
+ bestWord = w;
125
+ bestCount = c;
126
+ }
127
+ }
128
+ return { word: bestWord, key, files: g.files, suggestions: g.suggestions };
129
+ });
130
+ }
131
+ /**
132
+ * Run the interactive fix flow.
133
+ * Steps through each unique misspelled word and collects fix/ignore/skip decisions.
134
+ * Applies all changes after user confirmation.
135
+ */
136
+ export async function runInteractiveFix(misspellings, docsJsonPath, projectDir, spell) {
137
+ const grouped = groupMisspellings(misspellings);
138
+ const decisions = [];
139
+ console.log(`\n${grouped.length} unique misspelled words found.\n`);
140
+ let interrupted = false;
141
+ try {
142
+ let ignoreAllRemaining = false;
143
+ let skipAllRemaining = false;
144
+ for (let i = 0; i < grouped.length; i++) {
145
+ const { word, files, suggestions } = grouped[i];
146
+ const remaining = grouped.length - i;
147
+ if (ignoreAllRemaining) {
148
+ decisions.push({ action: 'ignore', word });
149
+ continue;
150
+ }
151
+ if (skipAllRemaining) {
152
+ decisions.push({ action: 'skip', word });
153
+ continue;
154
+ }
155
+ // Visual separator between words
156
+ if (i > 0) {
157
+ console.log('\n ─────────────────────────────────────\n');
158
+ }
159
+ // Display context
160
+ const fileList = files.slice(0, 5).map((f) => `${f.file}:${f.line}`).join(', ');
161
+ const moreCount = files.length - 5;
162
+ const fileDisplay = moreCount > 0 ? `${fileList}, ... and ${moreCount} more` : fileList;
163
+ console.log(` ${i + 1}/${grouped.length} "${word}" — found in ${files.length} file${files.length === 1 ? '' : 's'}`);
164
+ console.log(` ${fileDisplay}\n`);
165
+ // Compute suggestions on-demand if not already available
166
+ let wordSuggestions = suggestions;
167
+ if (wordSuggestions.length === 0 && spell) {
168
+ wordSuggestions = spell.suggest(word).slice(0, 3);
169
+ }
170
+ // Build choices with structured values
171
+ const choices = [];
172
+ for (let j = 0; j < wordSuggestions.length; j++) {
173
+ const label = j === 0 ? `Fix → ${wordSuggestions[j]} (recommended)` : `Fix → ${wordSuggestions[j]}`;
174
+ choices.push({ name: label, value: { action: 'fix', replacement: wordSuggestions[j] } });
175
+ }
176
+ choices.push({ name: 'Ignore in the future (add to docs.json)', value: { action: 'ignore' } });
177
+ choices.push({ name: 'Skip', value: { action: 'skip' } });
178
+ if (remaining >= 5 || wordSuggestions.length === 0) {
179
+ choices.push({ name: 'Ignore all remaining', value: { action: 'ignore-all' } });
180
+ choices.push({ name: 'Skip all remaining', value: { action: 'skip-all' } });
181
+ }
182
+ const answer = await select({
183
+ message: 'What do you want to do?',
184
+ choices,
185
+ loop: false,
186
+ });
187
+ if (answer.action === 'ignore-all') {
188
+ ignoreAllRemaining = true;
189
+ decisions.push({ action: 'ignore', word });
190
+ }
191
+ else if (answer.action === 'skip-all') {
192
+ skipAllRemaining = true;
193
+ decisions.push({ action: 'skip', word });
194
+ }
195
+ else if (answer.action === 'ignore') {
196
+ decisions.push({ action: 'ignore', word });
197
+ }
198
+ else if (answer.action === 'skip') {
199
+ decisions.push({ action: 'skip', word });
200
+ }
201
+ else if (answer.action === 'fix') {
202
+ decisions.push({ action: 'fix', word, replacement: answer.replacement });
203
+ }
204
+ }
205
+ }
206
+ catch (err) {
207
+ // Ctrl+C during prompts — apply decisions made so far
208
+ if (err instanceof Error && err.name === 'ExitPromptError') {
209
+ interrupted = true;
210
+ console.log('');
211
+ }
212
+ else {
213
+ throw err;
214
+ }
215
+ }
216
+ // Tally
217
+ const fixes = decisions.filter((d) => d.action === 'fix');
218
+ const ignores = decisions.filter((d) => d.action === 'ignore');
219
+ const skips = decisions.filter((d) => d.action === 'skip');
220
+ const reviewed = fixes.length + ignores.length + skips.length;
221
+ if (fixes.length === 0 && ignores.length === 0) {
222
+ console.log('\nNo changes to apply.');
223
+ return;
224
+ }
225
+ // Count affected files for fixes
226
+ const fixWords = new Set(fixes.map((f) => f.word.toLowerCase()));
227
+ const affectedFiles = new Set(misspellings.filter((m) => fixWords.has(m.word.toLowerCase())).map((m) => m.file));
228
+ // Summary
229
+ if (interrupted) {
230
+ console.log(`\nStopped early — reviewed ${reviewed} of ${grouped.length} words.\n`);
231
+ }
232
+ console.log('Summary:');
233
+ if (fixes.length > 0) {
234
+ console.log(` Fix: ${fixes.length} word${fixes.length === 1 ? '' : 's'} across ${affectedFiles.size} file${affectedFiles.size === 1 ? '' : 's'}`);
235
+ }
236
+ if (ignores.length > 0) {
237
+ console.log(` Ignore: ${ignores.length} word${ignores.length === 1 ? '' : 's'} (added to docs.json)`);
238
+ }
239
+ if (skips.length > 0) {
240
+ console.log(` Skip: ${skips.length} word${skips.length === 1 ? '' : 's'} (no changes)`);
241
+ }
242
+ if (interrupted && reviewed < grouped.length) {
243
+ console.log(` Not reviewed: ${grouped.length - reviewed} word${grouped.length - reviewed === 1 ? '' : 's'}`);
244
+ }
245
+ console.log('');
246
+ const confirmed = await confirm({
247
+ message: interrupted ? 'Apply changes made so far?' : 'Apply changes?',
248
+ default: true,
249
+ });
250
+ if (!confirmed) {
251
+ console.log('No changes applied.');
252
+ return;
253
+ }
254
+ // Apply fixes — batch per file
255
+ if (fixes.length > 0) {
256
+ const fixActions = fixes
257
+ .filter((f) => !!f.replacement)
258
+ .map((f) => ({ word: f.word, replacement: f.replacement }));
259
+ // Collect all affected file paths
260
+ const filePaths = new Set();
261
+ for (const m of misspellings) {
262
+ if (fixWords.has(m.word.toLowerCase())) {
263
+ filePaths.add(path.join(projectDir, m.file));
264
+ }
265
+ }
266
+ let filesFixed = 0;
267
+ for (const absPath of filePaths) {
268
+ try {
269
+ const content = await fs.readFile(absPath, 'utf8');
270
+ const modified = applyFixesToContent(content, fixActions);
271
+ if (modified !== content) {
272
+ await fs.writeFile(absPath, modified);
273
+ filesFixed++;
274
+ }
275
+ }
276
+ catch (err) {
277
+ const code = err.code;
278
+ if (code !== 'ENOENT') {
279
+ output.warn(`Could not fix ${absPath}: ${err.message}`);
280
+ }
281
+ }
282
+ }
283
+ output.success(`Fixed ${fixes.length} word${fixes.length === 1 ? '' : 's'} across ${filesFixed} file${filesFixed === 1 ? '' : 's'}`);
284
+ }
285
+ // Apply ignores
286
+ if (ignores.length > 0) {
287
+ const ignoreWordsList = ignores.map((d) => d.word);
288
+ await writeIgnoreWordsToDocsJson(docsJsonPath, ignoreWordsList);
289
+ output.success(`Added ${ignores.length} word${ignores.length === 1 ? '' : 's'} to spellcheck.ignore in docs.json`);
290
+ }
291
+ }
292
+ //# sourceMappingURL=spellcheck-fix.js.map