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.
- package/README.md +42 -0
- package/dist/__tests__/unit/docs-json-writer.test.js +59 -1
- package/dist/__tests__/unit/docs-json-writer.test.js.map +1 -1
- package/dist/__tests__/unit/spellcheck-fix.test.d.ts +2 -0
- package/dist/__tests__/unit/spellcheck-fix.test.d.ts.map +1 -0
- package/dist/__tests__/unit/spellcheck-fix.test.js +82 -0
- package/dist/__tests__/unit/spellcheck-fix.test.js.map +1 -0
- package/dist/__tests__/unit/spellcheck-utils.test.d.ts +2 -0
- package/dist/__tests__/unit/spellcheck-utils.test.d.ts.map +1 -0
- package/dist/__tests__/unit/spellcheck-utils.test.js +234 -0
- package/dist/__tests__/unit/spellcheck-utils.test.js.map +1 -0
- package/dist/__tests__/unit/tech-words.test.d.ts +2 -0
- package/dist/__tests__/unit/tech-words.test.d.ts.map +1 -0
- package/dist/__tests__/unit/tech-words.test.js +31 -0
- package/dist/__tests__/unit/tech-words.test.js.map +1 -0
- package/dist/commands/spellcheck.d.ts +13 -0
- package/dist/commands/spellcheck.d.ts.map +1 -0
- package/dist/commands/spellcheck.js +144 -0
- package/dist/commands/spellcheck.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/docs-json-writer.d.ts +6 -0
- package/dist/lib/docs-json-writer.d.ts.map +1 -1
- package/dist/lib/docs-json-writer.js +29 -0
- package/dist/lib/docs-json-writer.js.map +1 -1
- package/dist/lib/spellcheck-fix.d.ts +37 -0
- package/dist/lib/spellcheck-fix.d.ts.map +1 -0
- package/dist/lib/spellcheck-fix.js +292 -0
- package/dist/lib/spellcheck-fix.js.map +1 -0
- package/dist/lib/spellcheck-utils.d.ts +36 -0
- package/dist/lib/spellcheck-utils.d.ts.map +1 -0
- package/dist/lib/spellcheck-utils.js +138 -0
- package/dist/lib/spellcheck-utils.js.map +1 -0
- package/dist/lib/tech-words.d.ts +9 -0
- package/dist/lib/tech-words.d.ts.map +1 -0
- package/dist/lib/tech-words.js +118 -0
- package/dist/lib/tech-words.js.map +1 -0
- package/package.json +3 -1
- package/vendored/lib/static-file-route.ts +1 -1
- 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":"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"}
|
|
@@ -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
|