@cspell/eslint-plugin 5.18.5 → 5.19.0
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 +79 -2
- package/dist/index.d.ts +63 -2
- package/dist/index.js +226 -22
- package/dist/index.mjs +226 -23
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -1,3 +1,80 @@
|
|
|
1
|
-
#
|
|
1
|
+
# [WIP] CSpell ESLint Plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A spell checker plugin for ESLint based upon CSpell.
|
|
4
|
+
|
|
5
|
+
## [WIP] - Work In Progress
|
|
6
|
+
|
|
7
|
+
This plugin is still in active development. Due to the nature of how files are parsed, the `cspell` command line tool and this ESLint plugin will give different results. It is recommended that ESLint or `cspell` checks a file, but not both. Use `ignorePaths` setting in `cspell.json` to tell the `cspell` command line tool to ignore files checked by ESLint.
|
|
8
|
+
|
|
9
|
+
## Quick Setup
|
|
10
|
+
|
|
11
|
+
- Install `@cspell/eslint-plugin` as a dev-dependency
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install --save-dev @cspell/eslint-plugin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- Add to it to `.eslintrc.json`
|
|
18
|
+
```json
|
|
19
|
+
"extends": ["plugin:@cspell/recommended"]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
interface Options {
|
|
26
|
+
/**
|
|
27
|
+
* Number of spelling suggestions to make.
|
|
28
|
+
* @default 8
|
|
29
|
+
*/
|
|
30
|
+
numSuggestions: number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate suggestions
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
generateSuggestions: boolean;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Output debug logs
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
debugMode?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Ignore import and require names
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
ignoreImports?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Spell check identifiers (variables names, function names, and class names)
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
checkIdentifiers?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Spell check strings
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
checkStrings?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Spell check template strings
|
|
60
|
+
* @default true
|
|
61
|
+
*/
|
|
62
|
+
checkStringTemplates?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Spell check comments
|
|
65
|
+
* @default true
|
|
66
|
+
*/
|
|
67
|
+
checkComments?: boolean;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"plugins": ["@cspell"],
|
|
76
|
+
"rules": {
|
|
77
|
+
"@cspell/spellchecker": ["warn", { "checkComments": false }]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,69 @@
|
|
|
1
1
|
import { Rule } from 'eslint';
|
|
2
2
|
|
|
3
3
|
interface PluginRules {
|
|
4
|
-
['
|
|
4
|
+
['spellchecker']: Rule.RuleModule;
|
|
5
5
|
}
|
|
6
6
|
declare const rules: PluginRules;
|
|
7
|
+
declare const configs: {
|
|
8
|
+
recommended: {
|
|
9
|
+
plugins: string[];
|
|
10
|
+
rules: {
|
|
11
|
+
'@cspell/spellchecker': {}[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
debug: {
|
|
15
|
+
plugins: string[];
|
|
16
|
+
rules: {
|
|
17
|
+
'@cspell/spellchecker': (string | {
|
|
18
|
+
debugMode: boolean;
|
|
19
|
+
})[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
7
23
|
|
|
8
|
-
|
|
24
|
+
interface Options extends Check {
|
|
25
|
+
/**
|
|
26
|
+
* Number of spelling suggestions to make.
|
|
27
|
+
* @default 8
|
|
28
|
+
*/
|
|
29
|
+
numSuggestions: number;
|
|
30
|
+
/**
|
|
31
|
+
* Generate suggestions
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
generateSuggestions: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Output debug logs
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
debugMode?: boolean;
|
|
40
|
+
}
|
|
41
|
+
interface Check {
|
|
42
|
+
/**
|
|
43
|
+
* Ignore import and require names
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
ignoreImports?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Spell check identifiers (variables names, function names, and class names)
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
checkIdentifiers?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Spell check strings
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
checkStrings?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Spell check template strings
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
checkStringTemplates?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Spell check comments
|
|
64
|
+
* @default true
|
|
65
|
+
*/
|
|
66
|
+
checkComments?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { Options, configs, rules };
|
package/dist/index.js
CHANGED
|
@@ -10,17 +10,106 @@
|
|
|
10
10
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
11
11
|
|
|
12
12
|
var assert = require('assert');
|
|
13
|
-
var util = require('util');
|
|
14
13
|
var cspellLib = require('cspell-lib');
|
|
14
|
+
var util = require('util');
|
|
15
15
|
|
|
16
16
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
17
17
|
|
|
18
18
|
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
|
|
19
19
|
|
|
20
|
+
const defaultCheckOptions = {
|
|
21
|
+
checkComments: true,
|
|
22
|
+
checkIdentifiers: true,
|
|
23
|
+
checkStrings: true,
|
|
24
|
+
checkStringTemplates: true,
|
|
25
|
+
ignoreImports: true,
|
|
26
|
+
};
|
|
27
|
+
const defaultOptions = {
|
|
28
|
+
...defaultCheckOptions,
|
|
29
|
+
numSuggestions: 8,
|
|
30
|
+
generateSuggestions: true,
|
|
31
|
+
debugMode: false,
|
|
32
|
+
};
|
|
33
|
+
function normalizeOptions(opts) {
|
|
34
|
+
const options = Object.assign({}, defaultOptions, opts || {});
|
|
35
|
+
return options;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var $schema = "http://json-schema.org/draft-07/schema#";
|
|
39
|
+
var additionalProperties = false;
|
|
40
|
+
var definitions = {
|
|
41
|
+
};
|
|
42
|
+
var properties = {
|
|
43
|
+
checkComments: {
|
|
44
|
+
"default": true,
|
|
45
|
+
description: "Spell check comments",
|
|
46
|
+
type: "boolean"
|
|
47
|
+
},
|
|
48
|
+
checkIdentifiers: {
|
|
49
|
+
"default": true,
|
|
50
|
+
description: "Spell check identifiers (variables names, function names, and class names)",
|
|
51
|
+
type: "boolean"
|
|
52
|
+
},
|
|
53
|
+
checkStringTemplates: {
|
|
54
|
+
"default": true,
|
|
55
|
+
description: "Spell check template strings",
|
|
56
|
+
type: "boolean"
|
|
57
|
+
},
|
|
58
|
+
checkStrings: {
|
|
59
|
+
"default": true,
|
|
60
|
+
description: "Spell check strings",
|
|
61
|
+
type: "boolean"
|
|
62
|
+
},
|
|
63
|
+
debugMode: {
|
|
64
|
+
"default": false,
|
|
65
|
+
description: "Output debug logs",
|
|
66
|
+
type: "boolean"
|
|
67
|
+
},
|
|
68
|
+
generateSuggestions: {
|
|
69
|
+
"default": true,
|
|
70
|
+
description: "Generate suggestions",
|
|
71
|
+
type: "boolean"
|
|
72
|
+
},
|
|
73
|
+
ignoreImports: {
|
|
74
|
+
"default": true,
|
|
75
|
+
description: "Ignore import and require names",
|
|
76
|
+
type: "boolean"
|
|
77
|
+
},
|
|
78
|
+
numSuggestions: {
|
|
79
|
+
"default": 8,
|
|
80
|
+
description: "Number of spelling suggestions to make.",
|
|
81
|
+
type: "number"
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var required = [
|
|
85
|
+
"numSuggestions",
|
|
86
|
+
"generateSuggestions"
|
|
87
|
+
];
|
|
88
|
+
var type = "object";
|
|
89
|
+
var optionsSchema = {
|
|
90
|
+
$schema: $schema,
|
|
91
|
+
additionalProperties: additionalProperties,
|
|
92
|
+
definitions: definitions,
|
|
93
|
+
properties: properties,
|
|
94
|
+
required: required,
|
|
95
|
+
type: type
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const schema = optionsSchema;
|
|
99
|
+
const messages = {
|
|
100
|
+
wordUnknown: 'Unknown word: "{{word}}"',
|
|
101
|
+
wordForbidden: 'Forbidden word: "{{word}}"',
|
|
102
|
+
suggestWord: '{{word}}',
|
|
103
|
+
};
|
|
20
104
|
const meta = {
|
|
21
105
|
docs: {
|
|
22
|
-
description: 'CSpell',
|
|
106
|
+
description: 'CSpell spellchecker',
|
|
107
|
+
category: 'Possible Errors',
|
|
108
|
+
recommended: false,
|
|
23
109
|
},
|
|
110
|
+
messages,
|
|
111
|
+
hasSuggestions: true,
|
|
112
|
+
schema: [schema],
|
|
24
113
|
};
|
|
25
114
|
const defaultSettings = {
|
|
26
115
|
patterns: [
|
|
@@ -32,55 +121,106 @@ const defaultSettings = {
|
|
|
32
121
|
// },
|
|
33
122
|
],
|
|
34
123
|
};
|
|
35
|
-
|
|
124
|
+
let isDebugMode = false;
|
|
125
|
+
function log(...args) {
|
|
126
|
+
if (!isDebugMode)
|
|
127
|
+
return;
|
|
128
|
+
console.log(...args);
|
|
129
|
+
}
|
|
36
130
|
function create(context) {
|
|
131
|
+
const options = normalizeOptions(context.options[0]);
|
|
132
|
+
const importedIdentifiers = new Set();
|
|
133
|
+
isDebugMode = options.debugMode || false;
|
|
134
|
+
isDebugMode && logContext(context);
|
|
37
135
|
const doc = cspellLib.createTextDocument({ uri: context.getFilename(), content: context.getSourceCode().getText() });
|
|
38
|
-
const validator = new cspellLib.DocumentValidator(doc,
|
|
136
|
+
const validator = new cspellLib.DocumentValidator(doc, options, defaultSettings);
|
|
39
137
|
validator.prepareSync();
|
|
40
|
-
log(`
|
|
41
|
-
|
|
42
|
-
id: ${context.id}
|
|
43
|
-
cwd: ${context.getCwd()}
|
|
44
|
-
filename: ${context.getFilename()}
|
|
45
|
-
physicalFilename: ${context.getPhysicalFilename()}
|
|
46
|
-
scope: ${context.getScope().type}
|
|
47
|
-
`);
|
|
48
138
|
function checkLiteral(node) {
|
|
139
|
+
if (!options.checkStrings)
|
|
140
|
+
return;
|
|
49
141
|
if (typeof node.value === 'string') {
|
|
142
|
+
if (options.ignoreImports && isImportOrRequired(node))
|
|
143
|
+
return;
|
|
144
|
+
debugNode(node, node.value);
|
|
50
145
|
checkNodeText(node, node.value);
|
|
51
146
|
}
|
|
52
147
|
}
|
|
53
148
|
function checkTemplateElement(node) {
|
|
149
|
+
if (!options.checkStringTemplates)
|
|
150
|
+
return;
|
|
151
|
+
debugNode(node, node.value);
|
|
54
152
|
// console.log('Template: %o', node.value);
|
|
55
153
|
checkNodeText(node, node.value.cooked || node.value.raw);
|
|
56
154
|
}
|
|
57
155
|
function checkIdentifier(node) {
|
|
156
|
+
if (options.ignoreImports && isImportIdentifier(node)) {
|
|
157
|
+
importedIdentifiers.add(node.name);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!options.checkIdentifiers)
|
|
161
|
+
return;
|
|
162
|
+
if (importedIdentifiers.has(node.name))
|
|
163
|
+
return;
|
|
164
|
+
debugNode(node, node.name);
|
|
58
165
|
checkNodeText(node, node.name);
|
|
59
166
|
}
|
|
60
167
|
function checkComment(node) {
|
|
168
|
+
if (!options.checkComments)
|
|
169
|
+
return;
|
|
170
|
+
debugNode(node, node.value);
|
|
61
171
|
checkNodeText(node, node.value);
|
|
62
|
-
util.format('%o', node);
|
|
63
172
|
}
|
|
64
173
|
function checkNodeText(node, text) {
|
|
65
174
|
if (!node.range)
|
|
66
175
|
return;
|
|
67
176
|
const adj = node.type === 'Literal' ? 1 : 0;
|
|
68
177
|
const range = [node.range[0] + adj, node.range[1] - adj];
|
|
69
|
-
const scope =
|
|
178
|
+
const scope = calcScope();
|
|
70
179
|
const result = validator.checkText(range, text, scope);
|
|
71
180
|
result.forEach((issue) => reportIssue(issue));
|
|
72
181
|
}
|
|
182
|
+
function calcScope(_node) {
|
|
183
|
+
// inheritance(node);
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
function isImportIdentifier(node) {
|
|
187
|
+
const parent = node.parent;
|
|
188
|
+
if (node.type !== 'Identifier' || !parent)
|
|
189
|
+
return false;
|
|
190
|
+
return ((parent.type === 'ImportSpecifier' && parent.imported === node) ||
|
|
191
|
+
(parent.type === 'ExportSpecifier' && parent.local === node));
|
|
192
|
+
}
|
|
73
193
|
function reportIssue(issue) {
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
const
|
|
194
|
+
var _a;
|
|
195
|
+
const messageId = issue.isFlagged ? 'wordForbidden' : 'wordUnknown';
|
|
196
|
+
const data = {
|
|
197
|
+
word: issue.text,
|
|
198
|
+
};
|
|
77
199
|
const code = context.getSourceCode();
|
|
78
|
-
const start =
|
|
79
|
-
const end =
|
|
80
|
-
const
|
|
200
|
+
const start = issue.offset;
|
|
201
|
+
const end = issue.offset + (issue.length || issue.text.length);
|
|
202
|
+
const startPos = code.getLocFromIndex(start);
|
|
203
|
+
const endPos = code.getLocFromIndex(end);
|
|
204
|
+
const loc = { start: startPos, end: endPos };
|
|
205
|
+
function fixFactory(word) {
|
|
206
|
+
return (fixer) => fixer.replaceTextRange([start, end], word);
|
|
207
|
+
}
|
|
208
|
+
function createSug(word) {
|
|
209
|
+
const data = { word };
|
|
210
|
+
const messageId = 'suggestWord';
|
|
211
|
+
return {
|
|
212
|
+
messageId,
|
|
213
|
+
data,
|
|
214
|
+
fix: fixFactory(word),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
log('Suggestions: %o', issue.suggestions);
|
|
218
|
+
const suggest = (_a = issue.suggestions) === null || _a === void 0 ? void 0 : _a.map(createSug);
|
|
81
219
|
const des = {
|
|
82
|
-
|
|
220
|
+
messageId,
|
|
221
|
+
data,
|
|
83
222
|
loc,
|
|
223
|
+
suggest,
|
|
84
224
|
};
|
|
85
225
|
context.report(des);
|
|
86
226
|
}
|
|
@@ -105,6 +245,14 @@ scope: ${context.getScope().type}
|
|
|
105
245
|
const extra = node.source === child ? '.source' : '';
|
|
106
246
|
return node.type + extra;
|
|
107
247
|
}
|
|
248
|
+
if (node.type === 'ExportSpecifier') {
|
|
249
|
+
const extra = node.exported === child ? '.exported' : node.local === child ? '.local' : '';
|
|
250
|
+
return node.type + extra;
|
|
251
|
+
}
|
|
252
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
253
|
+
const extra = node.source === child ? '.source' : '';
|
|
254
|
+
return node.type + extra;
|
|
255
|
+
}
|
|
108
256
|
if (node.type === 'Property') {
|
|
109
257
|
const extra = node.key === child ? 'key' : node.value === child ? 'value' : '';
|
|
110
258
|
return [node.type, node.kind, extra].join('.');
|
|
@@ -125,15 +273,44 @@ scope: ${context.getScope().type}
|
|
|
125
273
|
const extra = node.id === child ? 'id' : node.body === child ? 'body' : 'superClass';
|
|
126
274
|
return node.type + '.' + extra;
|
|
127
275
|
}
|
|
276
|
+
if (node.type === 'CallExpression') {
|
|
277
|
+
const extra = node.callee === child ? 'callee' : 'arguments';
|
|
278
|
+
return node.type + '.' + extra;
|
|
279
|
+
}
|
|
128
280
|
if (node.type === 'Literal') {
|
|
129
281
|
return tagLiteral(node);
|
|
130
282
|
}
|
|
283
|
+
if (node.type === 'Block') {
|
|
284
|
+
return node.value[0] === '*' ? 'Comment.docBlock' : 'Comment.block';
|
|
285
|
+
}
|
|
286
|
+
if (node.type === 'Line') {
|
|
287
|
+
return 'Comment.line';
|
|
288
|
+
}
|
|
131
289
|
return node.type;
|
|
132
290
|
}
|
|
133
291
|
function inheritance(node) {
|
|
134
292
|
const a = [...context.getAncestors(), node];
|
|
135
293
|
return a.map(mapNode);
|
|
136
294
|
}
|
|
295
|
+
function inheritanceSummary(node) {
|
|
296
|
+
return inheritance(node).join(' ');
|
|
297
|
+
}
|
|
298
|
+
function isFunctionCall(node, name) {
|
|
299
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === name;
|
|
300
|
+
}
|
|
301
|
+
function isRequireCall(node) {
|
|
302
|
+
return isFunctionCall(node, 'require');
|
|
303
|
+
}
|
|
304
|
+
function isImportOrRequired(node) {
|
|
305
|
+
var _a;
|
|
306
|
+
return isRequireCall(node.parent) || (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === 'ImportDeclaration' && node.parent.source === node);
|
|
307
|
+
}
|
|
308
|
+
function debugNode(node, value) {
|
|
309
|
+
if (!isDebugMode)
|
|
310
|
+
return;
|
|
311
|
+
const val = util.format('%o', value);
|
|
312
|
+
log(`${inheritanceSummary(node)}: ${val}`);
|
|
313
|
+
}
|
|
137
314
|
}
|
|
138
315
|
function tagLiteral(node) {
|
|
139
316
|
var _a;
|
|
@@ -149,11 +326,38 @@ function tagLiteral(node) {
|
|
|
149
326
|
return node.type + '.' + extra;
|
|
150
327
|
}
|
|
151
328
|
const rules = {
|
|
152
|
-
|
|
329
|
+
spellchecker: {
|
|
153
330
|
meta,
|
|
154
331
|
create,
|
|
155
332
|
},
|
|
156
333
|
};
|
|
334
|
+
function logContext(context) {
|
|
335
|
+
log('\n\n************************');
|
|
336
|
+
// log(context.getSourceCode().text);
|
|
337
|
+
log(`
|
|
338
|
+
|
|
339
|
+
id: ${context.id}
|
|
340
|
+
cwd: ${context.getCwd()}
|
|
341
|
+
filename: ${context.getFilename()}
|
|
342
|
+
physicalFilename: ${context.getPhysicalFilename()}
|
|
343
|
+
scope: ${context.getScope().type}
|
|
344
|
+
`);
|
|
345
|
+
}
|
|
346
|
+
const configs = {
|
|
347
|
+
recommended: {
|
|
348
|
+
plugins: ['@cspell'],
|
|
349
|
+
rules: {
|
|
350
|
+
'@cspell/spellchecker': ['warn', {}],
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
debug: {
|
|
354
|
+
plugins: ['@cspell'],
|
|
355
|
+
rules: {
|
|
356
|
+
'@cspell/spellchecker': ['warn', { debugMode: true }],
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
};
|
|
157
360
|
|
|
361
|
+
exports.configs = configs;
|
|
158
362
|
exports.rules = rules;
|
|
159
363
|
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
CHANGED
|
@@ -6,13 +6,102 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import assert from 'assert';
|
|
9
|
-
import { format } from 'util';
|
|
10
9
|
import { createTextDocument, DocumentValidator } from 'cspell-lib';
|
|
10
|
+
import { format } from 'util';
|
|
11
|
+
|
|
12
|
+
const defaultCheckOptions = {
|
|
13
|
+
checkComments: true,
|
|
14
|
+
checkIdentifiers: true,
|
|
15
|
+
checkStrings: true,
|
|
16
|
+
checkStringTemplates: true,
|
|
17
|
+
ignoreImports: true,
|
|
18
|
+
};
|
|
19
|
+
const defaultOptions = {
|
|
20
|
+
...defaultCheckOptions,
|
|
21
|
+
numSuggestions: 8,
|
|
22
|
+
generateSuggestions: true,
|
|
23
|
+
debugMode: false,
|
|
24
|
+
};
|
|
25
|
+
function normalizeOptions(opts) {
|
|
26
|
+
const options = Object.assign({}, defaultOptions, opts || {});
|
|
27
|
+
return options;
|
|
28
|
+
}
|
|
11
29
|
|
|
30
|
+
var $schema = "http://json-schema.org/draft-07/schema#";
|
|
31
|
+
var additionalProperties = false;
|
|
32
|
+
var definitions = {
|
|
33
|
+
};
|
|
34
|
+
var properties = {
|
|
35
|
+
checkComments: {
|
|
36
|
+
"default": true,
|
|
37
|
+
description: "Spell check comments",
|
|
38
|
+
type: "boolean"
|
|
39
|
+
},
|
|
40
|
+
checkIdentifiers: {
|
|
41
|
+
"default": true,
|
|
42
|
+
description: "Spell check identifiers (variables names, function names, and class names)",
|
|
43
|
+
type: "boolean"
|
|
44
|
+
},
|
|
45
|
+
checkStringTemplates: {
|
|
46
|
+
"default": true,
|
|
47
|
+
description: "Spell check template strings",
|
|
48
|
+
type: "boolean"
|
|
49
|
+
},
|
|
50
|
+
checkStrings: {
|
|
51
|
+
"default": true,
|
|
52
|
+
description: "Spell check strings",
|
|
53
|
+
type: "boolean"
|
|
54
|
+
},
|
|
55
|
+
debugMode: {
|
|
56
|
+
"default": false,
|
|
57
|
+
description: "Output debug logs",
|
|
58
|
+
type: "boolean"
|
|
59
|
+
},
|
|
60
|
+
generateSuggestions: {
|
|
61
|
+
"default": true,
|
|
62
|
+
description: "Generate suggestions",
|
|
63
|
+
type: "boolean"
|
|
64
|
+
},
|
|
65
|
+
ignoreImports: {
|
|
66
|
+
"default": true,
|
|
67
|
+
description: "Ignore import and require names",
|
|
68
|
+
type: "boolean"
|
|
69
|
+
},
|
|
70
|
+
numSuggestions: {
|
|
71
|
+
"default": 8,
|
|
72
|
+
description: "Number of spelling suggestions to make.",
|
|
73
|
+
type: "number"
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var required = [
|
|
77
|
+
"numSuggestions",
|
|
78
|
+
"generateSuggestions"
|
|
79
|
+
];
|
|
80
|
+
var type = "object";
|
|
81
|
+
var optionsSchema = {
|
|
82
|
+
$schema: $schema,
|
|
83
|
+
additionalProperties: additionalProperties,
|
|
84
|
+
definitions: definitions,
|
|
85
|
+
properties: properties,
|
|
86
|
+
required: required,
|
|
87
|
+
type: type
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const schema = optionsSchema;
|
|
91
|
+
const messages = {
|
|
92
|
+
wordUnknown: 'Unknown word: "{{word}}"',
|
|
93
|
+
wordForbidden: 'Forbidden word: "{{word}}"',
|
|
94
|
+
suggestWord: '{{word}}',
|
|
95
|
+
};
|
|
12
96
|
const meta = {
|
|
13
97
|
docs: {
|
|
14
|
-
description: 'CSpell',
|
|
98
|
+
description: 'CSpell spellchecker',
|
|
99
|
+
category: 'Possible Errors',
|
|
100
|
+
recommended: false,
|
|
15
101
|
},
|
|
102
|
+
messages,
|
|
103
|
+
hasSuggestions: true,
|
|
104
|
+
schema: [schema],
|
|
16
105
|
};
|
|
17
106
|
const defaultSettings = {
|
|
18
107
|
patterns: [
|
|
@@ -24,55 +113,106 @@ const defaultSettings = {
|
|
|
24
113
|
// },
|
|
25
114
|
],
|
|
26
115
|
};
|
|
27
|
-
|
|
116
|
+
let isDebugMode = false;
|
|
117
|
+
function log(...args) {
|
|
118
|
+
if (!isDebugMode)
|
|
119
|
+
return;
|
|
120
|
+
console.log(...args);
|
|
121
|
+
}
|
|
28
122
|
function create(context) {
|
|
123
|
+
const options = normalizeOptions(context.options[0]);
|
|
124
|
+
const importedIdentifiers = new Set();
|
|
125
|
+
isDebugMode = options.debugMode || false;
|
|
126
|
+
isDebugMode && logContext(context);
|
|
29
127
|
const doc = createTextDocument({ uri: context.getFilename(), content: context.getSourceCode().getText() });
|
|
30
|
-
const validator = new DocumentValidator(doc,
|
|
128
|
+
const validator = new DocumentValidator(doc, options, defaultSettings);
|
|
31
129
|
validator.prepareSync();
|
|
32
|
-
log(`
|
|
33
|
-
|
|
34
|
-
id: ${context.id}
|
|
35
|
-
cwd: ${context.getCwd()}
|
|
36
|
-
filename: ${context.getFilename()}
|
|
37
|
-
physicalFilename: ${context.getPhysicalFilename()}
|
|
38
|
-
scope: ${context.getScope().type}
|
|
39
|
-
`);
|
|
40
130
|
function checkLiteral(node) {
|
|
131
|
+
if (!options.checkStrings)
|
|
132
|
+
return;
|
|
41
133
|
if (typeof node.value === 'string') {
|
|
134
|
+
if (options.ignoreImports && isImportOrRequired(node))
|
|
135
|
+
return;
|
|
136
|
+
debugNode(node, node.value);
|
|
42
137
|
checkNodeText(node, node.value);
|
|
43
138
|
}
|
|
44
139
|
}
|
|
45
140
|
function checkTemplateElement(node) {
|
|
141
|
+
if (!options.checkStringTemplates)
|
|
142
|
+
return;
|
|
143
|
+
debugNode(node, node.value);
|
|
46
144
|
// console.log('Template: %o', node.value);
|
|
47
145
|
checkNodeText(node, node.value.cooked || node.value.raw);
|
|
48
146
|
}
|
|
49
147
|
function checkIdentifier(node) {
|
|
148
|
+
if (options.ignoreImports && isImportIdentifier(node)) {
|
|
149
|
+
importedIdentifiers.add(node.name);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (!options.checkIdentifiers)
|
|
153
|
+
return;
|
|
154
|
+
if (importedIdentifiers.has(node.name))
|
|
155
|
+
return;
|
|
156
|
+
debugNode(node, node.name);
|
|
50
157
|
checkNodeText(node, node.name);
|
|
51
158
|
}
|
|
52
159
|
function checkComment(node) {
|
|
160
|
+
if (!options.checkComments)
|
|
161
|
+
return;
|
|
162
|
+
debugNode(node, node.value);
|
|
53
163
|
checkNodeText(node, node.value);
|
|
54
|
-
format('%o', node);
|
|
55
164
|
}
|
|
56
165
|
function checkNodeText(node, text) {
|
|
57
166
|
if (!node.range)
|
|
58
167
|
return;
|
|
59
168
|
const adj = node.type === 'Literal' ? 1 : 0;
|
|
60
169
|
const range = [node.range[0] + adj, node.range[1] - adj];
|
|
61
|
-
const scope =
|
|
170
|
+
const scope = calcScope();
|
|
62
171
|
const result = validator.checkText(range, text, scope);
|
|
63
172
|
result.forEach((issue) => reportIssue(issue));
|
|
64
173
|
}
|
|
174
|
+
function calcScope(_node) {
|
|
175
|
+
// inheritance(node);
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
function isImportIdentifier(node) {
|
|
179
|
+
const parent = node.parent;
|
|
180
|
+
if (node.type !== 'Identifier' || !parent)
|
|
181
|
+
return false;
|
|
182
|
+
return ((parent.type === 'ImportSpecifier' && parent.imported === node) ||
|
|
183
|
+
(parent.type === 'ExportSpecifier' && parent.local === node));
|
|
184
|
+
}
|
|
65
185
|
function reportIssue(issue) {
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
186
|
+
var _a;
|
|
187
|
+
const messageId = issue.isFlagged ? 'wordForbidden' : 'wordUnknown';
|
|
188
|
+
const data = {
|
|
189
|
+
word: issue.text,
|
|
190
|
+
};
|
|
69
191
|
const code = context.getSourceCode();
|
|
70
|
-
const start =
|
|
71
|
-
const end =
|
|
72
|
-
const
|
|
192
|
+
const start = issue.offset;
|
|
193
|
+
const end = issue.offset + (issue.length || issue.text.length);
|
|
194
|
+
const startPos = code.getLocFromIndex(start);
|
|
195
|
+
const endPos = code.getLocFromIndex(end);
|
|
196
|
+
const loc = { start: startPos, end: endPos };
|
|
197
|
+
function fixFactory(word) {
|
|
198
|
+
return (fixer) => fixer.replaceTextRange([start, end], word);
|
|
199
|
+
}
|
|
200
|
+
function createSug(word) {
|
|
201
|
+
const data = { word };
|
|
202
|
+
const messageId = 'suggestWord';
|
|
203
|
+
return {
|
|
204
|
+
messageId,
|
|
205
|
+
data,
|
|
206
|
+
fix: fixFactory(word),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
log('Suggestions: %o', issue.suggestions);
|
|
210
|
+
const suggest = (_a = issue.suggestions) === null || _a === void 0 ? void 0 : _a.map(createSug);
|
|
73
211
|
const des = {
|
|
74
|
-
|
|
212
|
+
messageId,
|
|
213
|
+
data,
|
|
75
214
|
loc,
|
|
215
|
+
suggest,
|
|
76
216
|
};
|
|
77
217
|
context.report(des);
|
|
78
218
|
}
|
|
@@ -97,6 +237,14 @@ scope: ${context.getScope().type}
|
|
|
97
237
|
const extra = node.source === child ? '.source' : '';
|
|
98
238
|
return node.type + extra;
|
|
99
239
|
}
|
|
240
|
+
if (node.type === 'ExportSpecifier') {
|
|
241
|
+
const extra = node.exported === child ? '.exported' : node.local === child ? '.local' : '';
|
|
242
|
+
return node.type + extra;
|
|
243
|
+
}
|
|
244
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
245
|
+
const extra = node.source === child ? '.source' : '';
|
|
246
|
+
return node.type + extra;
|
|
247
|
+
}
|
|
100
248
|
if (node.type === 'Property') {
|
|
101
249
|
const extra = node.key === child ? 'key' : node.value === child ? 'value' : '';
|
|
102
250
|
return [node.type, node.kind, extra].join('.');
|
|
@@ -117,15 +265,44 @@ scope: ${context.getScope().type}
|
|
|
117
265
|
const extra = node.id === child ? 'id' : node.body === child ? 'body' : 'superClass';
|
|
118
266
|
return node.type + '.' + extra;
|
|
119
267
|
}
|
|
268
|
+
if (node.type === 'CallExpression') {
|
|
269
|
+
const extra = node.callee === child ? 'callee' : 'arguments';
|
|
270
|
+
return node.type + '.' + extra;
|
|
271
|
+
}
|
|
120
272
|
if (node.type === 'Literal') {
|
|
121
273
|
return tagLiteral(node);
|
|
122
274
|
}
|
|
275
|
+
if (node.type === 'Block') {
|
|
276
|
+
return node.value[0] === '*' ? 'Comment.docBlock' : 'Comment.block';
|
|
277
|
+
}
|
|
278
|
+
if (node.type === 'Line') {
|
|
279
|
+
return 'Comment.line';
|
|
280
|
+
}
|
|
123
281
|
return node.type;
|
|
124
282
|
}
|
|
125
283
|
function inheritance(node) {
|
|
126
284
|
const a = [...context.getAncestors(), node];
|
|
127
285
|
return a.map(mapNode);
|
|
128
286
|
}
|
|
287
|
+
function inheritanceSummary(node) {
|
|
288
|
+
return inheritance(node).join(' ');
|
|
289
|
+
}
|
|
290
|
+
function isFunctionCall(node, name) {
|
|
291
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === name;
|
|
292
|
+
}
|
|
293
|
+
function isRequireCall(node) {
|
|
294
|
+
return isFunctionCall(node, 'require');
|
|
295
|
+
}
|
|
296
|
+
function isImportOrRequired(node) {
|
|
297
|
+
var _a;
|
|
298
|
+
return isRequireCall(node.parent) || (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === 'ImportDeclaration' && node.parent.source === node);
|
|
299
|
+
}
|
|
300
|
+
function debugNode(node, value) {
|
|
301
|
+
if (!isDebugMode)
|
|
302
|
+
return;
|
|
303
|
+
const val = format('%o', value);
|
|
304
|
+
log(`${inheritanceSummary(node)}: ${val}`);
|
|
305
|
+
}
|
|
129
306
|
}
|
|
130
307
|
function tagLiteral(node) {
|
|
131
308
|
var _a;
|
|
@@ -141,11 +318,37 @@ function tagLiteral(node) {
|
|
|
141
318
|
return node.type + '.' + extra;
|
|
142
319
|
}
|
|
143
320
|
const rules = {
|
|
144
|
-
|
|
321
|
+
spellchecker: {
|
|
145
322
|
meta,
|
|
146
323
|
create,
|
|
147
324
|
},
|
|
148
325
|
};
|
|
326
|
+
function logContext(context) {
|
|
327
|
+
log('\n\n************************');
|
|
328
|
+
// log(context.getSourceCode().text);
|
|
329
|
+
log(`
|
|
330
|
+
|
|
331
|
+
id: ${context.id}
|
|
332
|
+
cwd: ${context.getCwd()}
|
|
333
|
+
filename: ${context.getFilename()}
|
|
334
|
+
physicalFilename: ${context.getPhysicalFilename()}
|
|
335
|
+
scope: ${context.getScope().type}
|
|
336
|
+
`);
|
|
337
|
+
}
|
|
338
|
+
const configs = {
|
|
339
|
+
recommended: {
|
|
340
|
+
plugins: ['@cspell'],
|
|
341
|
+
rules: {
|
|
342
|
+
'@cspell/spellchecker': ['warn', {}],
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
debug: {
|
|
346
|
+
plugins: ['@cspell'],
|
|
347
|
+
rules: {
|
|
348
|
+
'@cspell/spellchecker': ['warn', { debugMode: true }],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
};
|
|
149
352
|
|
|
150
|
-
export { rules };
|
|
353
|
+
export { configs, rules };
|
|
151
354
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "5.
|
|
6
|
+
"version": "5.19.0",
|
|
7
7
|
"description": "[WIP] CSpell ESLint plugin",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"cspell",
|
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
"!**/*.map"
|
|
34
34
|
],
|
|
35
35
|
"scripts": {
|
|
36
|
-
"build": "
|
|
37
|
-
"
|
|
36
|
+
"build": "npm run build-schema && npm run build-rollup",
|
|
37
|
+
"build-rollup": "rollup --config rollup.config.ts --configPlugin typescript",
|
|
38
|
+
"build-schema": "ts-json-schema-generator --no-top-ref --path src/options.ts --type Options -o ./src/_auto_generated_/options.schema.json",
|
|
39
|
+
"watch": "npm run build-rollup -- --watch",
|
|
38
40
|
"clean": "rimraf dist coverage .tsbuildinfo",
|
|
39
41
|
"clean-build": "npm run clean && npm run build",
|
|
40
42
|
"coverage": "echo coverage",
|
|
@@ -53,6 +55,7 @@
|
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|
|
55
57
|
"@rollup/plugin-commonjs": "^21.0.2",
|
|
58
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
56
59
|
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
57
60
|
"@rollup/plugin-typescript": "^8.3.1",
|
|
58
61
|
"@types/eslint": "^8.4.1",
|
|
@@ -61,13 +64,15 @@
|
|
|
61
64
|
"@typescript-eslint/parser": "^5.14.0",
|
|
62
65
|
"@typescript-eslint/types": "^5.14.0",
|
|
63
66
|
"@typescript-eslint/typescript-estree": "^5.14.0",
|
|
64
|
-
"eslint": "^8.
|
|
65
|
-
"mocha": "^9.2.
|
|
67
|
+
"eslint": "^8.11.0",
|
|
68
|
+
"mocha": "^9.2.2",
|
|
66
69
|
"rimraf": "^3.0.2",
|
|
67
70
|
"rollup": "^2.70.0",
|
|
68
|
-
"rollup-plugin-dts": "^4.2.0"
|
|
71
|
+
"rollup-plugin-dts": "^4.2.0",
|
|
72
|
+
"ts-json-schema-generator": "^0.98.0"
|
|
69
73
|
},
|
|
70
74
|
"dependencies": {
|
|
71
|
-
"cspell-lib": "^5.
|
|
72
|
-
}
|
|
75
|
+
"cspell-lib": "^5.19.0"
|
|
76
|
+
},
|
|
77
|
+
"gitHead": "7873efe40a3287d3e025f705e1712c12d3cb392e"
|
|
73
78
|
}
|