@nx/eslint 0.0.0-pr-22179-271588f
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/LICENSE +22 -0
- package/README.md +66 -0
- package/executors.json +10 -0
- package/generators.json +28 -0
- package/index.d.ts +4 -0
- package/index.js +14 -0
- package/migrations.json +138 -0
- package/package.json +52 -0
- package/plugin.d.ts +1 -0
- package/plugin.js +5 -0
- package/src/executors/lint/hasher.d.ts +9 -0
- package/src/executors/lint/hasher.js +43 -0
- package/src/executors/lint/lint.impl.d.ts +5 -0
- package/src/executors/lint/lint.impl.js +174 -0
- package/src/executors/lint/schema.d.ts +40 -0
- package/src/executors/lint/schema.json +148 -0
- package/src/executors/lint/utility/eslint-utils.d.ts +6 -0
- package/src/executors/lint/utility/eslint-utils.js +75 -0
- package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +11 -0
- package/src/generators/convert-to-flat-config/converters/json-converter.js +175 -0
- package/src/generators/convert-to-flat-config/generator.d.ts +4 -0
- package/src/generators/convert-to-flat-config/generator.js +139 -0
- package/src/generators/convert-to-flat-config/schema.d.ts +3 -0
- package/src/generators/convert-to-flat-config/schema.json +17 -0
- package/src/generators/init/global-eslint-config.d.ts +29 -0
- package/src/generators/init/global-eslint-config.js +102 -0
- package/src/generators/init/init-migration.d.ts +3 -0
- package/src/generators/init/init-migration.js +137 -0
- package/src/generators/init/init.d.ts +9 -0
- package/src/generators/init/init.js +93 -0
- package/src/generators/init/schema.json +28 -0
- package/src/generators/lint-project/lint-project.d.ts +22 -0
- package/src/generators/lint-project/lint-project.js +227 -0
- package/src/generators/lint-project/setup-root-eslint.d.ts +7 -0
- package/src/generators/lint-project/setup-root-eslint.js +33 -0
- package/src/generators/utils/eslint-file.d.ts +16 -0
- package/src/generators/utils/eslint-file.js +287 -0
- package/src/generators/utils/eslint-targets.d.ts +2 -0
- package/src/generators/utils/eslint-targets.js +18 -0
- package/src/generators/utils/flat-config/ast-utils.d.ts +60 -0
- package/src/generators/utils/flat-config/ast-utils.js +573 -0
- package/src/generators/utils/flat-config/path-utils.d.ts +3 -0
- package/src/generators/utils/flat-config/path-utils.js +28 -0
- package/src/generators/utils/linter.d.ts +4 -0
- package/src/generators/utils/linter.js +8 -0
- package/src/generators/utils/plugin.d.ts +2 -0
- package/src/generators/utils/plugin.js +11 -0
- package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -0
- package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +37 -0
- package/src/generators/workspace-rule/schema.json +26 -0
- package/src/generators/workspace-rule/workspace-rule.d.ts +6 -0
- package/src/generators/workspace-rule/workspace-rule.js +78 -0
- package/src/generators/workspace-rules-project/files/index.ts__tmpl__ +27 -0
- package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +14 -0
- package/src/generators/workspace-rules-project/files/tsconfig.lint.json__tmpl__ +9 -0
- package/src/generators/workspace-rules-project/schema.json +23 -0
- package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +8 -0
- package/src/generators/workspace-rules-project/workspace-rules-project.js +82 -0
- package/src/migrations/update-15-0-0/add-eslint-inputs.d.ts +2 -0
- package/src/migrations/update-15-0-0/add-eslint-inputs.js +27 -0
- package/src/migrations/update-15-7-1/add-eslint-ignore.d.ts +2 -0
- package/src/migrations/update-15-7-1/add-eslint-ignore.js +36 -0
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +9 -0
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +2 -0
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +44 -0
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +2 -0
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +47 -0
- package/src/migrations/update-17-1-0/update-typescript-eslint.d.ts +2 -0
- package/src/migrations/update-17-1-0/update-typescript-eslint.js +74 -0
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.d.ts +2 -0
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.js +46 -0
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.d.ts +2 -0
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.js +107 -0
- package/src/plugins/plugin.d.ts +5 -0
- package/src/plugins/plugin.js +92 -0
- package/src/utils/config-file.d.ts +5 -0
- package/src/utils/config-file.js +35 -0
- package/src/utils/flat-config.d.ts +2 -0
- package/src/utils/flat-config.js +7 -0
- package/src/utils/rules-requiring-type-checking.d.ts +3 -0
- package/src/utils/rules-requiring-type-checking.js +84 -0
- package/src/utils/versions.d.ts +5 -0
- package/src/utils/versions.js +8 -0
- package/src/utils/workspace-lint-rules.d.ts +1 -0
- package/src/utils/workspace-lint-rules.js +5 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAst = exports.mapFilePaths = exports.generateFlatOverride = exports.generateRequire = exports.stringifyNodeList = exports.generatePluginExtendsElement = exports.generateSpreadElement = exports.createNodeList = exports.addCompatToFlatConfig = exports.addPluginsToExportsBlock = exports.removeCompatExtends = exports.removePlugin = exports.addBlockToFlatConfigExport = exports.addImportToFlatConfig = exports.replaceOverride = exports.hasOverride = exports.removeOverridesFromLintConfig = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const ts = require("typescript");
|
|
6
|
+
const path_utils_1 = require("./path-utils");
|
|
7
|
+
/**
|
|
8
|
+
* Remove all overrides from the config file
|
|
9
|
+
*/
|
|
10
|
+
function removeOverridesFromLintConfig(content) {
|
|
11
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
12
|
+
const exportsArray = findAllBlocks(source);
|
|
13
|
+
if (!exportsArray) {
|
|
14
|
+
return content;
|
|
15
|
+
}
|
|
16
|
+
const changes = [];
|
|
17
|
+
exportsArray.forEach((node, i) => {
|
|
18
|
+
if (isOverride(node)) {
|
|
19
|
+
const commaOffset = i < exportsArray.length - 1 || exportsArray.hasTrailingComma ? 1 : 0;
|
|
20
|
+
changes.push({
|
|
21
|
+
type: devkit_1.ChangeType.Delete,
|
|
22
|
+
start: node.pos,
|
|
23
|
+
length: node.end - node.pos + commaOffset,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return (0, devkit_1.applyChangesToString)(content, changes);
|
|
28
|
+
}
|
|
29
|
+
exports.removeOverridesFromLintConfig = removeOverridesFromLintConfig;
|
|
30
|
+
function findAllBlocks(source) {
|
|
31
|
+
return ts.forEachChild(source, function analyze(node) {
|
|
32
|
+
if (ts.isExpressionStatement(node) &&
|
|
33
|
+
ts.isBinaryExpression(node.expression) &&
|
|
34
|
+
node.expression.left.getText() === 'module.exports' &&
|
|
35
|
+
ts.isArrayLiteralExpression(node.expression.right)) {
|
|
36
|
+
return node.expression.right.elements;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function isOverride(node) {
|
|
41
|
+
return ((ts.isObjectLiteralExpression(node) &&
|
|
42
|
+
node.properties.some((p) => p.name.getText() === 'files')) ||
|
|
43
|
+
// detect ...compat.config(...).map(...)
|
|
44
|
+
(ts.isSpreadElement(node) &&
|
|
45
|
+
ts.isCallExpression(node.expression) &&
|
|
46
|
+
ts.isPropertyAccessExpression(node.expression.expression) &&
|
|
47
|
+
ts.isArrowFunction(node.expression.arguments[0]) &&
|
|
48
|
+
ts.isParenthesizedExpression(node.expression.arguments[0].body)));
|
|
49
|
+
}
|
|
50
|
+
function hasOverride(content, lookup) {
|
|
51
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
52
|
+
const exportsArray = findAllBlocks(source);
|
|
53
|
+
if (!exportsArray) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
for (const node of exportsArray) {
|
|
57
|
+
if (isOverride(node)) {
|
|
58
|
+
let objSource;
|
|
59
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
60
|
+
objSource = node.getFullText();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const fullNodeText = node['expression'].arguments[0].body.expression.getFullText();
|
|
64
|
+
// strip any spread elements
|
|
65
|
+
objSource = fullNodeText.replace(/\s*\.\.\.[a-zA-Z0-9_]+,?\n?/, '');
|
|
66
|
+
}
|
|
67
|
+
const data = (0, devkit_1.parseJson)(objSource
|
|
68
|
+
// ensure property names have double quotes so that JSON.parse works
|
|
69
|
+
.replace(/'/g, '"')
|
|
70
|
+
.replace(/\s([a-zA-Z0-9_]+)\s*:/g, ' "$1": '));
|
|
71
|
+
if (lookup(data)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
exports.hasOverride = hasOverride;
|
|
79
|
+
const STRIP_SPREAD_ELEMENTS = /\s*\.\.\.[a-zA-Z0-9_]+,?\n?/g;
|
|
80
|
+
function parseTextToJson(text) {
|
|
81
|
+
return (0, devkit_1.parseJson)(text
|
|
82
|
+
// ensure property names have double quotes so that JSON.parse works
|
|
83
|
+
.replace(/'/g, '"')
|
|
84
|
+
.replace(/\s([a-zA-Z0-9_]+)\s*:/g, ' "$1": '));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Finds an override matching the lookup function and applies the update function to it
|
|
88
|
+
*/
|
|
89
|
+
function replaceOverride(content, root, lookup, update) {
|
|
90
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
91
|
+
const exportsArray = findAllBlocks(source);
|
|
92
|
+
if (!exportsArray) {
|
|
93
|
+
return content;
|
|
94
|
+
}
|
|
95
|
+
const changes = [];
|
|
96
|
+
exportsArray.forEach((node) => {
|
|
97
|
+
if (isOverride(node)) {
|
|
98
|
+
let objSource;
|
|
99
|
+
let start, end;
|
|
100
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
101
|
+
objSource = node.getFullText();
|
|
102
|
+
start = node.properties.pos + 1; // keep leading line break
|
|
103
|
+
end = node.properties.end;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const fullNodeText = node['expression'].arguments[0].body.expression.getFullText();
|
|
107
|
+
// strip any spread elements
|
|
108
|
+
objSource = fullNodeText.replace(STRIP_SPREAD_ELEMENTS, '');
|
|
109
|
+
start =
|
|
110
|
+
node['expression'].arguments[0].body.expression.properties.pos +
|
|
111
|
+
(fullNodeText.length - objSource.length);
|
|
112
|
+
end = node['expression'].arguments[0].body.expression.properties.end;
|
|
113
|
+
}
|
|
114
|
+
const data = parseTextToJson(objSource);
|
|
115
|
+
if (lookup(data)) {
|
|
116
|
+
changes.push({
|
|
117
|
+
type: devkit_1.ChangeType.Delete,
|
|
118
|
+
start,
|
|
119
|
+
length: end - start,
|
|
120
|
+
});
|
|
121
|
+
const updatedData = update(data);
|
|
122
|
+
if (updatedData) {
|
|
123
|
+
mapFilePaths(updatedData);
|
|
124
|
+
changes.push({
|
|
125
|
+
type: devkit_1.ChangeType.Insert,
|
|
126
|
+
index: start,
|
|
127
|
+
text: JSON.stringify(updatedData, null, 2).slice(2, -2), // remove curly braces and start/end line breaks since we are injecting just properties
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return (0, devkit_1.applyChangesToString)(content, changes);
|
|
134
|
+
}
|
|
135
|
+
exports.replaceOverride = replaceOverride;
|
|
136
|
+
/**
|
|
137
|
+
* Adding require statement to the top of the file
|
|
138
|
+
*/
|
|
139
|
+
function addImportToFlatConfig(content, variable, imp) {
|
|
140
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
141
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
142
|
+
const foundBindingVars = ts.forEachChild(source, function analyze(node) {
|
|
143
|
+
// we can only combine object binding patterns
|
|
144
|
+
if (!Array.isArray(variable)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (ts.isVariableStatement(node) &&
|
|
148
|
+
ts.isVariableDeclaration(node.declarationList.declarations[0]) &&
|
|
149
|
+
ts.isObjectBindingPattern(node.declarationList.declarations[0].name) &&
|
|
150
|
+
ts.isCallExpression(node.declarationList.declarations[0].initializer) &&
|
|
151
|
+
node.declarationList.declarations[0].initializer.expression.getText() ===
|
|
152
|
+
'require' &&
|
|
153
|
+
ts.isStringLiteral(node.declarationList.declarations[0].initializer.arguments[0]) &&
|
|
154
|
+
node.declarationList.declarations[0].initializer.arguments[0].text ===
|
|
155
|
+
imp) {
|
|
156
|
+
return node.declarationList.declarations[0].name.elements;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
if (foundBindingVars && Array.isArray(variable)) {
|
|
160
|
+
const newVariables = variable.filter((v) => !foundBindingVars.some((fv) => v === fv.name.getText()));
|
|
161
|
+
if (newVariables.length === 0) {
|
|
162
|
+
return content;
|
|
163
|
+
}
|
|
164
|
+
const isMultiLine = foundBindingVars.hasTrailingComma;
|
|
165
|
+
const pos = foundBindingVars.end;
|
|
166
|
+
const nodes = ts.factory.createNodeArray(newVariables.map((v) => ts.factory.createBindingElement(undefined, undefined, v)));
|
|
167
|
+
const insert = printer.printList(ts.ListFormat.ObjectBindingPatternElements, nodes, source);
|
|
168
|
+
return (0, devkit_1.applyChangesToString)(content, [
|
|
169
|
+
{
|
|
170
|
+
type: devkit_1.ChangeType.Insert,
|
|
171
|
+
index: pos,
|
|
172
|
+
text: isMultiLine ? `,\n${insert}` : `,${insert}`,
|
|
173
|
+
},
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
const hasSameIdentifierVar = ts.forEachChild(source, function analyze(node) {
|
|
177
|
+
// we are searching for a single variable
|
|
178
|
+
if (Array.isArray(variable)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (ts.isVariableStatement(node) &&
|
|
182
|
+
ts.isVariableDeclaration(node.declarationList.declarations[0]) &&
|
|
183
|
+
ts.isIdentifier(node.declarationList.declarations[0].name) &&
|
|
184
|
+
node.declarationList.declarations[0].name.getText() === variable &&
|
|
185
|
+
ts.isCallExpression(node.declarationList.declarations[0].initializer) &&
|
|
186
|
+
node.declarationList.declarations[0].initializer.expression.getText() ===
|
|
187
|
+
'require' &&
|
|
188
|
+
ts.isStringLiteral(node.declarationList.declarations[0].initializer.arguments[0]) &&
|
|
189
|
+
node.declarationList.declarations[0].initializer.arguments[0].text ===
|
|
190
|
+
imp) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
if (hasSameIdentifierVar) {
|
|
195
|
+
return content;
|
|
196
|
+
}
|
|
197
|
+
// the import was not found, create a new one
|
|
198
|
+
const requireStatement = generateRequire(typeof variable === 'string'
|
|
199
|
+
? variable
|
|
200
|
+
: ts.factory.createObjectBindingPattern(variable.map((v) => ts.factory.createBindingElement(undefined, undefined, v))), imp);
|
|
201
|
+
const insert = printer.printNode(ts.EmitHint.Unspecified, requireStatement, source);
|
|
202
|
+
return (0, devkit_1.applyChangesToString)(content, [
|
|
203
|
+
{
|
|
204
|
+
type: devkit_1.ChangeType.Insert,
|
|
205
|
+
index: 0,
|
|
206
|
+
text: `${insert}\n`,
|
|
207
|
+
},
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
exports.addImportToFlatConfig = addImportToFlatConfig;
|
|
211
|
+
/**
|
|
212
|
+
* Injects new ts.expression to the end of the module.exports array.
|
|
213
|
+
*/
|
|
214
|
+
function addBlockToFlatConfigExport(content, config, options = {
|
|
215
|
+
insertAtTheEnd: true,
|
|
216
|
+
}) {
|
|
217
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
218
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
219
|
+
const exportsArray = ts.forEachChild(source, function analyze(node) {
|
|
220
|
+
if (ts.isExpressionStatement(node) &&
|
|
221
|
+
ts.isBinaryExpression(node.expression) &&
|
|
222
|
+
node.expression.left.getText() === 'module.exports' &&
|
|
223
|
+
ts.isArrayLiteralExpression(node.expression.right)) {
|
|
224
|
+
return node.expression.right.elements;
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
const insert = printer.printNode(ts.EmitHint.Expression, config, source);
|
|
228
|
+
if (options.insertAtTheEnd) {
|
|
229
|
+
const index = exportsArray.length > 0
|
|
230
|
+
? exportsArray.at(exportsArray.length - 1).end
|
|
231
|
+
: exportsArray.pos;
|
|
232
|
+
return (0, devkit_1.applyChangesToString)(content, [
|
|
233
|
+
{
|
|
234
|
+
type: devkit_1.ChangeType.Insert,
|
|
235
|
+
index,
|
|
236
|
+
text: `,\n${insert}`,
|
|
237
|
+
},
|
|
238
|
+
]);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
const index = exportsArray.length > 0 ? exportsArray.at(0).pos : exportsArray.pos;
|
|
242
|
+
return (0, devkit_1.applyChangesToString)(content, [
|
|
243
|
+
{
|
|
244
|
+
type: devkit_1.ChangeType.Insert,
|
|
245
|
+
index,
|
|
246
|
+
text: `\n${insert},`,
|
|
247
|
+
},
|
|
248
|
+
]);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.addBlockToFlatConfigExport = addBlockToFlatConfigExport;
|
|
252
|
+
function removePlugin(content, pluginName, pluginImport) {
|
|
253
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
254
|
+
const changes = [];
|
|
255
|
+
ts.forEachChild(source, function analyze(node) {
|
|
256
|
+
if (ts.isVariableStatement(node) &&
|
|
257
|
+
ts.isVariableDeclaration(node.declarationList.declarations[0]) &&
|
|
258
|
+
ts.isCallExpression(node.declarationList.declarations[0].initializer) &&
|
|
259
|
+
node.declarationList.declarations[0].initializer.arguments.length &&
|
|
260
|
+
ts.isStringLiteral(node.declarationList.declarations[0].initializer.arguments[0]) &&
|
|
261
|
+
node.declarationList.declarations[0].initializer.arguments[0].text ===
|
|
262
|
+
pluginImport) {
|
|
263
|
+
changes.push({
|
|
264
|
+
type: devkit_1.ChangeType.Delete,
|
|
265
|
+
start: node.pos,
|
|
266
|
+
length: node.end - node.pos,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
ts.forEachChild(source, function analyze(node) {
|
|
271
|
+
if (ts.isExpressionStatement(node) &&
|
|
272
|
+
ts.isBinaryExpression(node.expression) &&
|
|
273
|
+
node.expression.left.getText() === 'module.exports' &&
|
|
274
|
+
ts.isArrayLiteralExpression(node.expression.right)) {
|
|
275
|
+
const blockElements = node.expression.right.elements;
|
|
276
|
+
blockElements.forEach((element) => {
|
|
277
|
+
if (ts.isObjectLiteralExpression(element)) {
|
|
278
|
+
const pluginsElem = element.properties.find((prop) => prop.name?.getText() === 'plugins');
|
|
279
|
+
if (!pluginsElem) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (ts.isArrayLiteralExpression(pluginsElem.initializer)) {
|
|
283
|
+
const pluginsArray = pluginsElem.initializer;
|
|
284
|
+
const plugins = parseTextToJson(pluginsElem.initializer
|
|
285
|
+
.getText()
|
|
286
|
+
.replace(STRIP_SPREAD_ELEMENTS, ''));
|
|
287
|
+
if (plugins.length > 1) {
|
|
288
|
+
changes.push({
|
|
289
|
+
type: devkit_1.ChangeType.Delete,
|
|
290
|
+
start: pluginsArray.pos,
|
|
291
|
+
length: pluginsArray.end - pluginsArray.pos,
|
|
292
|
+
});
|
|
293
|
+
changes.push({
|
|
294
|
+
type: devkit_1.ChangeType.Insert,
|
|
295
|
+
index: pluginsArray.pos,
|
|
296
|
+
text: JSON.stringify(plugins.filter((p) => p !== pluginName)),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
const keys = element.properties.map((prop) => prop.name?.getText());
|
|
301
|
+
if (keys.length > 1) {
|
|
302
|
+
const removeComma = keys.indexOf('plugins') < keys.length - 1 ||
|
|
303
|
+
element.properties.hasTrailingComma;
|
|
304
|
+
changes.push({
|
|
305
|
+
type: devkit_1.ChangeType.Delete,
|
|
306
|
+
start: pluginsElem.pos + (removeComma ? 1 : 0),
|
|
307
|
+
length: pluginsElem.end - pluginsElem.pos + (removeComma ? 1 : 0),
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
const removeComma = blockElements.indexOf(element) < blockElements.length - 1 ||
|
|
312
|
+
blockElements.hasTrailingComma;
|
|
313
|
+
changes.push({
|
|
314
|
+
type: devkit_1.ChangeType.Delete,
|
|
315
|
+
start: element.pos + (removeComma ? 1 : 0),
|
|
316
|
+
length: element.end - element.pos + (removeComma ? 1 : 0),
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else if (ts.isObjectLiteralExpression(pluginsElem.initializer)) {
|
|
322
|
+
const pluginsObj = pluginsElem.initializer;
|
|
323
|
+
if (pluginsElem.initializer.properties.length > 1) {
|
|
324
|
+
const plugin = pluginsObj.properties.find((prop) => prop.name?.['text'] === pluginName);
|
|
325
|
+
const removeComma = pluginsObj.properties.indexOf(plugin) <
|
|
326
|
+
pluginsObj.properties.length - 1 ||
|
|
327
|
+
pluginsObj.properties.hasTrailingComma;
|
|
328
|
+
changes.push({
|
|
329
|
+
type: devkit_1.ChangeType.Delete,
|
|
330
|
+
start: plugin.pos + (removeComma ? 1 : 0),
|
|
331
|
+
length: plugin.end - plugin.pos + (removeComma ? 1 : 0),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
const keys = element.properties.map((prop) => prop.name?.getText());
|
|
336
|
+
if (keys.length > 1) {
|
|
337
|
+
const removeComma = keys.indexOf('plugins') < keys.length - 1 ||
|
|
338
|
+
element.properties.hasTrailingComma;
|
|
339
|
+
changes.push({
|
|
340
|
+
type: devkit_1.ChangeType.Delete,
|
|
341
|
+
start: pluginsElem.pos + (removeComma ? 1 : 0),
|
|
342
|
+
length: pluginsElem.end - pluginsElem.pos + (removeComma ? 1 : 0),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
const removeComma = blockElements.indexOf(element) < blockElements.length - 1 ||
|
|
347
|
+
blockElements.hasTrailingComma;
|
|
348
|
+
changes.push({
|
|
349
|
+
type: devkit_1.ChangeType.Delete,
|
|
350
|
+
start: element.pos + (removeComma ? 1 : 0),
|
|
351
|
+
length: element.end - element.pos + (removeComma ? 1 : 0),
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
return (0, devkit_1.applyChangesToString)(content, changes);
|
|
361
|
+
}
|
|
362
|
+
exports.removePlugin = removePlugin;
|
|
363
|
+
function removeCompatExtends(content, compatExtends) {
|
|
364
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
365
|
+
const changes = [];
|
|
366
|
+
findAllBlocks(source).forEach((node) => {
|
|
367
|
+
if (ts.isSpreadElement(node) &&
|
|
368
|
+
ts.isCallExpression(node.expression) &&
|
|
369
|
+
ts.isArrowFunction(node.expression.arguments[0]) &&
|
|
370
|
+
ts.isParenthesizedExpression(node.expression.arguments[0].body) &&
|
|
371
|
+
ts.isPropertyAccessExpression(node.expression.expression) &&
|
|
372
|
+
ts.isCallExpression(node.expression.expression.expression)) {
|
|
373
|
+
const callExp = node.expression.expression.expression;
|
|
374
|
+
if (((callExp.expression.getText() === 'compat.config' &&
|
|
375
|
+
callExp.arguments[0].getText().includes('extends')) ||
|
|
376
|
+
callExp.expression.getText() === 'compat.extends') &&
|
|
377
|
+
compatExtends.some((ext) => callExp.arguments[0].getText().includes(ext))) {
|
|
378
|
+
// remove the whole node
|
|
379
|
+
changes.push({
|
|
380
|
+
type: devkit_1.ChangeType.Delete,
|
|
381
|
+
start: node.pos,
|
|
382
|
+
length: node.end - node.pos,
|
|
383
|
+
});
|
|
384
|
+
// and replace it with new one
|
|
385
|
+
const paramName = node.expression.arguments[0].parameters[0].name.getText();
|
|
386
|
+
const body = node.expression.arguments[0].body.expression.getFullText();
|
|
387
|
+
changes.push({
|
|
388
|
+
type: devkit_1.ChangeType.Insert,
|
|
389
|
+
index: node.pos,
|
|
390
|
+
text: '\n' +
|
|
391
|
+
body.replace(new RegExp('[ \t]s*...' + paramName + '[ \t]*,?\\s*', 'g'), ''),
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
return (0, devkit_1.applyChangesToString)(content, changes);
|
|
397
|
+
}
|
|
398
|
+
exports.removeCompatExtends = removeCompatExtends;
|
|
399
|
+
/**
|
|
400
|
+
* Add plugins block to the top of the export blocks
|
|
401
|
+
*/
|
|
402
|
+
function addPluginsToExportsBlock(content, plugins) {
|
|
403
|
+
const pluginsBlock = ts.factory.createObjectLiteralExpression([
|
|
404
|
+
ts.factory.createPropertyAssignment('plugins', ts.factory.createObjectLiteralExpression(plugins.map(({ name, varName }) => {
|
|
405
|
+
return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), ts.factory.createIdentifier(varName));
|
|
406
|
+
}))),
|
|
407
|
+
], false);
|
|
408
|
+
return addBlockToFlatConfigExport(content, pluginsBlock, {
|
|
409
|
+
insertAtTheEnd: false,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
exports.addPluginsToExportsBlock = addPluginsToExportsBlock;
|
|
413
|
+
/**
|
|
414
|
+
* Adds compat if missing to flat config
|
|
415
|
+
*/
|
|
416
|
+
function addCompatToFlatConfig(content) {
|
|
417
|
+
let result = content;
|
|
418
|
+
result = addImportToFlatConfig(result, 'js', '@eslint/js');
|
|
419
|
+
if (result.includes('const compat = new FlatCompat')) {
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
result = addImportToFlatConfig(result, 'FlatCompat', '@eslint/eslintrc');
|
|
423
|
+
const index = result.indexOf('module.exports');
|
|
424
|
+
return (0, devkit_1.applyChangesToString)(result, [
|
|
425
|
+
{
|
|
426
|
+
type: devkit_1.ChangeType.Insert,
|
|
427
|
+
index: index - 1,
|
|
428
|
+
text: `${DEFAULT_FLAT_CONFIG}\n`,
|
|
429
|
+
},
|
|
430
|
+
]);
|
|
431
|
+
}
|
|
432
|
+
exports.addCompatToFlatConfig = addCompatToFlatConfig;
|
|
433
|
+
const DEFAULT_FLAT_CONFIG = `
|
|
434
|
+
const compat = new FlatCompat({
|
|
435
|
+
baseDirectory: __dirname,
|
|
436
|
+
recommendedConfig: js.configs.recommended,
|
|
437
|
+
});
|
|
438
|
+
`;
|
|
439
|
+
/**
|
|
440
|
+
* Generate node list representing the imports and the exports blocks
|
|
441
|
+
* Optionally add flat compat initialization
|
|
442
|
+
*/
|
|
443
|
+
function createNodeList(importsMap, exportElements, isFlatCompatNeeded) {
|
|
444
|
+
const importsList = [];
|
|
445
|
+
if (isFlatCompatNeeded) {
|
|
446
|
+
importsMap.set('@eslint/js', 'js');
|
|
447
|
+
importsList.push(generateRequire(ts.factory.createObjectBindingPattern([
|
|
448
|
+
ts.factory.createBindingElement(undefined, undefined, 'FlatCompat'),
|
|
449
|
+
]), '@eslint/eslintrc'));
|
|
450
|
+
}
|
|
451
|
+
// generateRequire(varName, imp, ts.factory);
|
|
452
|
+
Array.from(importsMap.entries()).forEach(([imp, varName]) => {
|
|
453
|
+
importsList.push(generateRequire(varName, imp));
|
|
454
|
+
});
|
|
455
|
+
return ts.factory.createNodeArray([
|
|
456
|
+
// add plugin imports
|
|
457
|
+
...importsList,
|
|
458
|
+
ts.createSourceFile('', isFlatCompatNeeded ? DEFAULT_FLAT_CONFIG : '', ts.ScriptTarget.Latest, false, ts.ScriptKind.JS),
|
|
459
|
+
// creates:
|
|
460
|
+
// module.exports = [ ... ];
|
|
461
|
+
ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('module'), ts.factory.createIdentifier('exports')), ts.factory.createToken(ts.SyntaxKind.EqualsToken), ts.factory.createArrayLiteralExpression(exportElements, true))),
|
|
462
|
+
]);
|
|
463
|
+
}
|
|
464
|
+
exports.createNodeList = createNodeList;
|
|
465
|
+
function generateSpreadElement(name) {
|
|
466
|
+
return ts.factory.createSpreadElement(ts.factory.createIdentifier(name));
|
|
467
|
+
}
|
|
468
|
+
exports.generateSpreadElement = generateSpreadElement;
|
|
469
|
+
function generatePluginExtendsElement(plugins) {
|
|
470
|
+
return ts.factory.createSpreadElement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('compat'), ts.factory.createIdentifier('extends')), undefined, plugins.map((plugin) => ts.factory.createStringLiteral(plugin))));
|
|
471
|
+
}
|
|
472
|
+
exports.generatePluginExtendsElement = generatePluginExtendsElement;
|
|
473
|
+
/**
|
|
474
|
+
* Stringifies TS nodes to file content string
|
|
475
|
+
*/
|
|
476
|
+
function stringifyNodeList(nodes) {
|
|
477
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
478
|
+
const resultFile = ts.createSourceFile('', '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
479
|
+
return (printer
|
|
480
|
+
.printList(ts.ListFormat.MultiLine, nodes, resultFile)
|
|
481
|
+
// add new line before compat initialization
|
|
482
|
+
.replace(/const compat = new FlatCompat/, '\nconst compat = new FlatCompat')
|
|
483
|
+
// add new line before module.exports = ...
|
|
484
|
+
.replace(/module\.exports/, '\nmodule.exports'));
|
|
485
|
+
}
|
|
486
|
+
exports.stringifyNodeList = stringifyNodeList;
|
|
487
|
+
/**
|
|
488
|
+
* generates AST require statement
|
|
489
|
+
*/
|
|
490
|
+
function generateRequire(variableName, imp) {
|
|
491
|
+
return ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList([
|
|
492
|
+
ts.factory.createVariableDeclaration(variableName, undefined, undefined, ts.factory.createCallExpression(ts.factory.createIdentifier('require'), undefined, [ts.factory.createStringLiteral(imp)])),
|
|
493
|
+
], ts.NodeFlags.Const));
|
|
494
|
+
}
|
|
495
|
+
exports.generateRequire = generateRequire;
|
|
496
|
+
/**
|
|
497
|
+
* Generates AST object or spread element based on JSON override object
|
|
498
|
+
*/
|
|
499
|
+
function generateFlatOverride(override) {
|
|
500
|
+
mapFilePaths(override);
|
|
501
|
+
if (!override.env &&
|
|
502
|
+
!override.extends &&
|
|
503
|
+
!override.plugins &&
|
|
504
|
+
!override.parser) {
|
|
505
|
+
return generateAst(override);
|
|
506
|
+
}
|
|
507
|
+
const { files, excludedFiles, rules, ...rest } = override;
|
|
508
|
+
const objectLiteralElements = [
|
|
509
|
+
ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')),
|
|
510
|
+
];
|
|
511
|
+
addTSObjectProperty(objectLiteralElements, 'files', files);
|
|
512
|
+
addTSObjectProperty(objectLiteralElements, 'excludedFiles', excludedFiles);
|
|
513
|
+
addTSObjectProperty(objectLiteralElements, 'rules', rules);
|
|
514
|
+
return ts.factory.createSpreadElement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('compat'), ts.factory.createIdentifier('config')), undefined, [generateAst(rest)]), ts.factory.createIdentifier('map')), undefined, [
|
|
515
|
+
ts.factory.createArrowFunction(undefined, undefined, [
|
|
516
|
+
ts.factory.createParameterDeclaration(undefined, undefined, 'config'),
|
|
517
|
+
], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createParenthesizedExpression(ts.factory.createObjectLiteralExpression(objectLiteralElements, true))),
|
|
518
|
+
]));
|
|
519
|
+
}
|
|
520
|
+
exports.generateFlatOverride = generateFlatOverride;
|
|
521
|
+
function mapFilePaths(override) {
|
|
522
|
+
if (override.files) {
|
|
523
|
+
override.files = Array.isArray(override.files)
|
|
524
|
+
? override.files
|
|
525
|
+
: [override.files];
|
|
526
|
+
override.files = override.files.map((file) => (0, path_utils_1.mapFilePath)(file));
|
|
527
|
+
}
|
|
528
|
+
if (override.excludedFiles) {
|
|
529
|
+
override.excludedFiles = Array.isArray(override.excludedFiles)
|
|
530
|
+
? override.excludedFiles
|
|
531
|
+
: [override.excludedFiles];
|
|
532
|
+
override.excludedFiles = override.excludedFiles.map((file) => (0, path_utils_1.mapFilePath)(file));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
exports.mapFilePaths = mapFilePaths;
|
|
536
|
+
function addTSObjectProperty(elements, key, value) {
|
|
537
|
+
if (value) {
|
|
538
|
+
elements.push(ts.factory.createPropertyAssignment(key, generateAst(value)));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Generates an AST from a JSON-type input
|
|
543
|
+
*/
|
|
544
|
+
function generateAst(input) {
|
|
545
|
+
if (Array.isArray(input)) {
|
|
546
|
+
return ts.factory.createArrayLiteralExpression(input.map((item) => generateAst(item)), input.length > 1 // multiline only if more than one item
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
if (input === null) {
|
|
550
|
+
return ts.factory.createNull();
|
|
551
|
+
}
|
|
552
|
+
if (typeof input === 'object') {
|
|
553
|
+
return ts.factory.createObjectLiteralExpression(Object.entries(input)
|
|
554
|
+
.filter(([_, value]) => value !== undefined)
|
|
555
|
+
.map(([key, value]) => ts.factory.createPropertyAssignment(isValidKey(key) ? key : ts.factory.createStringLiteral(key), generateAst(value))), Object.keys(input).length > 1 // multiline only if more than one property
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
if (typeof input === 'string') {
|
|
559
|
+
return ts.factory.createStringLiteral(input);
|
|
560
|
+
}
|
|
561
|
+
if (typeof input === 'number') {
|
|
562
|
+
return ts.factory.createNumericLiteral(input);
|
|
563
|
+
}
|
|
564
|
+
if (typeof input === 'boolean') {
|
|
565
|
+
return (input ? ts.factory.createTrue() : ts.factory.createFalse());
|
|
566
|
+
}
|
|
567
|
+
// since we are parsing JSON, this should never happen
|
|
568
|
+
throw new Error(`Unknown type: ${typeof input} `);
|
|
569
|
+
}
|
|
570
|
+
exports.generateAst = generateAst;
|
|
571
|
+
function isValidKey(key) {
|
|
572
|
+
return /^[a-zA-Z0-9_]+$/.test(key);
|
|
573
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapFilePath = exports.updateFiles = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
function updateFiles(override) {
|
|
6
|
+
if (override.files) {
|
|
7
|
+
override.files = Array.isArray(override.files)
|
|
8
|
+
? override.files
|
|
9
|
+
: [override.files];
|
|
10
|
+
override.files = override.files.map((file) => mapFilePath(file));
|
|
11
|
+
}
|
|
12
|
+
return override;
|
|
13
|
+
}
|
|
14
|
+
exports.updateFiles = updateFiles;
|
|
15
|
+
function mapFilePath(filePath) {
|
|
16
|
+
if (filePath.startsWith('!')) {
|
|
17
|
+
const fileWithoutBang = filePath.slice(1);
|
|
18
|
+
if (fileWithoutBang.startsWith('*.')) {
|
|
19
|
+
return `!${(0, devkit_1.joinPathFragments)('**', fileWithoutBang)}`;
|
|
20
|
+
}
|
|
21
|
+
return filePath;
|
|
22
|
+
}
|
|
23
|
+
if (filePath.startsWith('*.')) {
|
|
24
|
+
return (0, devkit_1.joinPathFragments)('**', filePath);
|
|
25
|
+
}
|
|
26
|
+
return filePath;
|
|
27
|
+
}
|
|
28
|
+
exports.mapFilePath = mapFilePath;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasEslintPlugin = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
function hasEslintPlugin(tree) {
|
|
6
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
7
|
+
return nxJson.plugins?.some((p) => typeof p === 'string'
|
|
8
|
+
? p === '@nx/eslint/plugin'
|
|
9
|
+
: p.plugin === '@nx/eslint/plugin');
|
|
10
|
+
}
|
|
11
|
+
exports.hasEslintPlugin = hasEslintPlugin;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
import { rule, RULE_NAME } from './<%= name %>';
|
|
3
|
+
|
|
4
|
+
const ruleTester = new TSESLint.RuleTester({
|
|
5
|
+
parser: require.resolve('@typescript-eslint/parser'),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
ruleTester.run(RULE_NAME, rule, {
|
|
9
|
+
valid: [`const example = true;`],
|
|
10
|
+
invalid: [],
|
|
11
|
+
});
|