@angular-eslint/schematics 15.2.2-alpha.8 → 16.0.0-alpha.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/dist/add-eslint-to-project/index.js +13 -19
- package/dist/application/index.js +12 -23
- package/dist/application/schema.json +6 -0
- package/dist/collection.json +2 -1
- package/dist/convert-tslint-to-eslint/index.js +8 -516
- package/dist/library/index.js +12 -23
- package/dist/migrations/update-16-0-0/update-16-0-0.js +62 -0
- package/dist/migrations.json +5 -0
- package/dist/utils.js +106 -54
- package/dist/workspace/index.js +0 -1
- package/package.json +8 -7
- package/dist/convert-tslint-to-eslint/convert-to-eslint-config.js +0 -119
- package/dist/convert-tslint-to-eslint/schema.json +0 -39
- package/dist/convert-tslint-to-eslint/utils.js +0 -118
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const devkit_1 = require("@nx/devkit");
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
`
|
|
5
|
+
exports.default = (0, devkit_1.convertNxGenerator)(async (tree, options) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const projectName = (0, utils_1.determineTargetProjectName__NX)(tree, options.project);
|
|
8
|
+
if (!projectName) {
|
|
9
|
+
throw new Error('\n' +
|
|
10
|
+
`
|
|
12
11
|
Error: You must specify a project to add ESLint to because you have multiple projects in your angular.json
|
|
13
12
|
|
|
14
13
|
E.g. npx ng g @angular-eslint/schematics:add-eslint-to-project {{YOUR_PROJECT_NAME_GOES_HERE}}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
(0, utils_1.createESLintConfigForProject)(projectName, (_a = schema.setParserOptionsProject) !== null && _a !== void 0 ? _a : false),
|
|
22
|
-
]);
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
exports.default = addESLintToProject;
|
|
14
|
+
`.trim());
|
|
15
|
+
}
|
|
16
|
+
// Update the lint builder and config in angular.json
|
|
17
|
+
(0, utils_1.addESLintTargetToProject__NX)(tree, projectName, 'lint');
|
|
18
|
+
(0, utils_1.createESLintConfigForProject__NX)(tree, projectName, (_a = options.setParserOptionsProject) !== null && _a !== void 0 ? _a : false);
|
|
19
|
+
});
|
|
@@ -11,28 +11,17 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
const
|
|
14
|
+
const devkit_1 = require("@nx/devkit");
|
|
15
|
+
const ngcli_adapter_1 = require("@nx/devkit/ngcli-adapter");
|
|
15
16
|
const utils_1 = require("../utils");
|
|
16
|
-
|
|
17
|
+
exports.default = (0, devkit_1.convertNxGenerator)(async (tree, options) => {
|
|
17
18
|
var _a;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
function default_1(options) {
|
|
28
|
-
return (host, context) => {
|
|
29
|
-
// Remove angular-eslint specific options before passing to the Angular schematic
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
-
const { setParserOptionsProject } = options, angularOptions = __rest(options, ["setParserOptionsProject"]);
|
|
32
|
-
return (0, schematics_1.chain)([
|
|
33
|
-
(0, schematics_1.externalSchematic)('@schematics/angular', 'application', angularOptions),
|
|
34
|
-
eslintRelatedChanges(options),
|
|
35
|
-
])(host, context);
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
exports.default = default_1;
|
|
19
|
+
// Remove angular-eslint specific options before passing to the Angular schematic
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
+
const { setParserOptionsProject } = options, angularOptions = __rest(options, ["setParserOptionsProject"]);
|
|
22
|
+
const applicationGenerator = (0, ngcli_adapter_1.wrapAngularDevkitSchematic)('@schematics/angular', 'application');
|
|
23
|
+
await applicationGenerator(tree, angularOptions);
|
|
24
|
+
// Update the lint builder and config in angular.json
|
|
25
|
+
(0, utils_1.addESLintTargetToProject__NX)(tree, options.name, 'lint');
|
|
26
|
+
(0, utils_1.createESLintConfigForProject__NX)(tree, options.name, (_a = options.setParserOptionsProject) !== null && _a !== void 0 ? _a : false);
|
|
27
|
+
});
|
|
@@ -106,6 +106,12 @@
|
|
|
106
106
|
"type": "boolean",
|
|
107
107
|
"default": true
|
|
108
108
|
},
|
|
109
|
+
"standalone": {
|
|
110
|
+
"description": "Creates an application based upon the standalone API, without NgModules.",
|
|
111
|
+
"type": "boolean",
|
|
112
|
+
"default": false,
|
|
113
|
+
"x-user-analytics": "ep.ng_standalone"
|
|
114
|
+
},
|
|
109
115
|
"setParserOptionsProject": {
|
|
110
116
|
"type": "boolean",
|
|
111
117
|
"description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
|
package/dist/collection.json
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"convert-tslint-to-eslint": {
|
|
16
16
|
"factory": "./convert-tslint-to-eslint",
|
|
17
17
|
"schema": "./convert-tslint-to-eslint/schema.json",
|
|
18
|
-
"description": "Convert the given project's TSLint setup to an equivalent ESLint one"
|
|
18
|
+
"description": "Convert the given project's TSLint setup to an equivalent ESLint one",
|
|
19
|
+
"hidden": true
|
|
19
20
|
},
|
|
20
21
|
"application": {
|
|
21
22
|
"aliases": ["app"],
|
|
@@ -1,521 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
9
|
-
const eslintPlugin = require('@angular-eslint/eslint-plugin');
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
11
|
-
const eslintPluginTemplate = require('@angular-eslint/eslint-plugin-template');
|
|
12
|
-
const eslintPluginConfigBaseOriginal = eslintPlugin.configs.base;
|
|
13
|
-
const eslintPluginConfigNgCliCompatOriginal = eslintPlugin.configs['ng-cli-compat'];
|
|
14
|
-
const eslintPluginConfigNgCliCompatFormattingAddOnOriginal = eslintPlugin.configs['ng-cli-compat--formatting-add-on'];
|
|
15
|
-
const eslintPluginTemplateConfigRecommendedOriginal = eslintPluginTemplate.configs.recommended;
|
|
16
|
-
function convert(schema) {
|
|
17
|
-
return (tree) => {
|
|
18
|
-
if (tree.exists('tsconfig.base.json')) {
|
|
19
|
-
throw new Error('\nError: Angular CLI v10.1.0 and later (and no `tsconfig.base.json`) is required in order to run this schematic. Please update your workspace and try again.\n');
|
|
20
|
-
}
|
|
21
|
-
const projectName = (0, utils_1.determineTargetProjectName)(tree, schema.project);
|
|
22
|
-
if (!projectName) {
|
|
23
|
-
throw new Error('\n' +
|
|
24
|
-
`
|
|
25
|
-
Error: You must specify a project to convert because you have multiple projects in your angular.json
|
|
3
|
+
function default_1() {
|
|
4
|
+
return () => {
|
|
5
|
+
throw new Error('\n' +
|
|
6
|
+
`
|
|
7
|
+
Error: The \`convert-tslint-to-eslint\` schematic is no longer supported.
|
|
26
8
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
const { root: projectRoot, projectType } = (0, utils_1.getProjectConfig)(tree, projectName);
|
|
31
|
-
// Default Angular CLI project at the root of the workspace
|
|
32
|
-
const isRootAngularProject = projectRoot === '';
|
|
33
|
-
// May or may not exist yet depending on if this is the root project, or a later one from projects/
|
|
34
|
-
const rootESLintrcJsonPath = (0, core_1.join)((0, core_1.normalize)(tree.root.path), '.eslintrc.json');
|
|
35
|
-
// Already exists, will be converted
|
|
36
|
-
const projectTSLintJsonPath = (0, core_1.join)((0, core_1.normalize)(projectRoot), 'tslint.json');
|
|
37
|
-
return (0, schematics_1.chain)([
|
|
38
|
-
// Overwrite the "lint" target directly for the selected project in the angular.json
|
|
39
|
-
(0, utils_1.addESLintTargetToProject)(projectName, 'lint'),
|
|
40
|
-
ensureRootESLintConfig(schema, tree, projectName, rootESLintrcJsonPath),
|
|
41
|
-
(0, convert_to_eslint_config_1.convertTSLintDisableCommentsForProject)(projectName),
|
|
42
|
-
isRootAngularProject || schema.ignoreExistingTslintConfig
|
|
43
|
-
? (0, schematics_1.noop)()
|
|
44
|
-
: removeExtendsFromProjectTSLintConfigBeforeConverting(tree, projectTSLintJsonPath),
|
|
45
|
-
isRootAngularProject
|
|
46
|
-
? (0, schematics_1.noop)()
|
|
47
|
-
: schema.ignoreExistingTslintConfig
|
|
48
|
-
? (0, schematics_1.chain)([
|
|
49
|
-
// Create the latest recommended ESLint config file for the project
|
|
50
|
-
(0, utils_1.createESLintConfigForProject)(projectName, true),
|
|
51
|
-
// Delete the TSLint config file for the project
|
|
52
|
-
(0, utils_1.removeTSLintJSONForProject)(projectName),
|
|
53
|
-
])
|
|
54
|
-
: convertNonRootTSLintConfig(schema, projectRoot, projectType, projectTSLintJsonPath, rootESLintrcJsonPath),
|
|
55
|
-
function cleanUpTSLintIfNoLongerInUse(tree) {
|
|
56
|
-
if (schema.removeTslintIfNoMoreTslintTargets &&
|
|
57
|
-
!(0, utils_1.isTSLintUsedInWorkspace)(tree)) {
|
|
58
|
-
tree.delete((0, core_1.join)((0, core_1.normalize)(tree.root.path), 'tslint.json'));
|
|
59
|
-
return (0, schematics_1.chain)([
|
|
60
|
-
/**
|
|
61
|
-
* Update the schematicCollections to prefer @angular-eslint so that future projects within
|
|
62
|
-
* the same workspace will also use ESLint
|
|
63
|
-
*/
|
|
64
|
-
(0, utils_1.updateJsonInTree)((0, utils_1.getWorkspacePath)(tree), (json) => (0, utils_1.updateSchematicCollections)(json)),
|
|
65
|
-
(0, utils_2.uninstallTSLintAndCodelyzer)(),
|
|
66
|
-
]);
|
|
67
|
-
}
|
|
68
|
-
return undefined;
|
|
69
|
-
},
|
|
70
|
-
]);
|
|
9
|
+
Please see https://github.com/angular-eslint/angular-eslint/blob/main/docs/MIGRATING_FROM_TSLINT.md
|
|
10
|
+
`.trim());
|
|
71
11
|
};
|
|
72
12
|
}
|
|
73
|
-
exports.default =
|
|
74
|
-
/**
|
|
75
|
-
* Because the Angular CLI supports multi-project workspaces we could be in a situation
|
|
76
|
-
* where the user is converting a project which is not the standard one at the root of
|
|
77
|
-
* the workspace, and they have not previously converted their root project (or it doesn't
|
|
78
|
-
* exist because they generated their workspace with no default app and only use the projects/
|
|
79
|
-
* directory).
|
|
80
|
-
*
|
|
81
|
-
* We therefore need to ensure that, before we convert a specific project, we have a root level
|
|
82
|
-
* .eslintrc.json available to us to extend from.
|
|
83
|
-
*/
|
|
84
|
-
function ensureRootESLintConfig(schema, tree, projectName, rootESLintrcJsonPath) {
|
|
85
|
-
const hasExistingRootESLintrcConfig = tree.exists(rootESLintrcJsonPath);
|
|
86
|
-
if (hasExistingRootESLintrcConfig) {
|
|
87
|
-
return (0, schematics_1.noop)();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* When ignoreExistingTslintConfig is set, Do not perform a conversion of the root
|
|
91
|
-
* TSLint config and instead switch the workspace directly to using the latest
|
|
92
|
-
* recommended ESLint config.
|
|
93
|
-
*/
|
|
94
|
-
if (schema.ignoreExistingTslintConfig) {
|
|
95
|
-
const workspaceJson = (0, utils_1.readJsonInTree)(tree, (0, utils_1.getWorkspacePath)(tree));
|
|
96
|
-
const prefix = workspaceJson.projects[projectName].prefix || 'app';
|
|
97
|
-
return (0, utils_1.updateJsonInTree)(rootESLintrcJsonPath, () => ({
|
|
98
|
-
root: true,
|
|
99
|
-
// Each additional project is linted independently
|
|
100
|
-
ignorePatterns: ['projects/**/*'],
|
|
101
|
-
overrides: [
|
|
102
|
-
{
|
|
103
|
-
files: ['*.ts'],
|
|
104
|
-
parserOptions: {
|
|
105
|
-
project: ['tsconfig.json', 'e2e/tsconfig.json'],
|
|
106
|
-
createDefaultProgram: true,
|
|
107
|
-
},
|
|
108
|
-
extends: [
|
|
109
|
-
'plugin:@angular-eslint/recommended',
|
|
110
|
-
'plugin:@angular-eslint/template/process-inline-templates',
|
|
111
|
-
],
|
|
112
|
-
rules: {
|
|
113
|
-
'@angular-eslint/component-selector': [
|
|
114
|
-
'error',
|
|
115
|
-
{
|
|
116
|
-
prefix,
|
|
117
|
-
style: 'kebab-case',
|
|
118
|
-
type: 'element',
|
|
119
|
-
},
|
|
120
|
-
],
|
|
121
|
-
'@angular-eslint/directive-selector': [
|
|
122
|
-
'error',
|
|
123
|
-
{
|
|
124
|
-
prefix,
|
|
125
|
-
style: 'camelCase',
|
|
126
|
-
type: 'attribute',
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
files: ['*.html'],
|
|
133
|
-
extends: ['plugin:@angular-eslint/template/recommended'],
|
|
134
|
-
rules: {},
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
}));
|
|
138
|
-
}
|
|
139
|
-
return convertRootTSLintConfig(schema, 'tslint.json', rootESLintrcJsonPath);
|
|
140
|
-
}
|
|
141
|
-
function convertRootTSLintConfig(schema, rootTSLintJsonPath, rootESLintrcJsonPath) {
|
|
142
|
-
return async (tree, context) => {
|
|
143
|
-
const rawRootTSLintJson = (0, utils_1.readJsonInTree)(tree, rootTSLintJsonPath);
|
|
144
|
-
const convertToESLintConfig = (0, convert_to_eslint_config_1.createConvertToESLintConfig)(context);
|
|
145
|
-
const convertedRoot = await convertToESLintConfig('tslint.json', rawRootTSLintJson);
|
|
146
|
-
const convertedRootESLintConfig = convertedRoot.convertedESLintConfig;
|
|
147
|
-
warnInCaseOfUnconvertedRules(context, rootTSLintJsonPath, convertedRoot.unconvertedTSLintRules);
|
|
148
|
-
// We mutate these as part of the transformations, so make copies first
|
|
149
|
-
const eslintPluginConfigBase = Object.assign({}, eslintPluginConfigBaseOriginal);
|
|
150
|
-
const eslintPluginConfigNgCliCompat = Object.assign({}, eslintPluginConfigNgCliCompatOriginal);
|
|
151
|
-
const eslintPluginConfigNgCliCompatFormattingAddOn = Object.assign({}, eslintPluginConfigNgCliCompatFormattingAddOnOriginal);
|
|
152
|
-
const eslintPluginTemplateConfigRecommended = Object.assign({}, eslintPluginTemplateConfigRecommendedOriginal);
|
|
153
|
-
/**
|
|
154
|
-
* Force these 2 rules to be defined in the user's .eslintrc.json by removing
|
|
155
|
-
* them from the comparison config before deduping
|
|
156
|
-
*/
|
|
157
|
-
delete eslintPluginConfigNgCliCompat.rules['@angular-eslint/directive-selector'];
|
|
158
|
-
delete eslintPluginConfigNgCliCompat.rules['@angular-eslint/component-selector'];
|
|
159
|
-
removeUndesiredRulesFromConfig(convertedRootESLintConfig);
|
|
160
|
-
adjustSomeRuleConfigs(convertedRootESLintConfig);
|
|
161
|
-
handleFormattingRules(schema, context, convertedRootESLintConfig);
|
|
162
|
-
/**
|
|
163
|
-
* To avoid users' configs being bigger and more verbose than necessary, we perform some
|
|
164
|
-
* deduplication against our underlying ng-cli-compat configuration that they will extend from.
|
|
165
|
-
*/
|
|
166
|
-
dedupePluginsAgainstConfigs(convertedRootESLintConfig, [
|
|
167
|
-
eslintPluginConfigBase,
|
|
168
|
-
eslintPluginConfigNgCliCompat,
|
|
169
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
170
|
-
{
|
|
171
|
-
plugins: [
|
|
172
|
-
'@angular-eslint/eslint-plugin',
|
|
173
|
-
'@angular-eslint/eslint-plugin-template',
|
|
174
|
-
'@typescript-eslint/tslint', // see note on not depending on not wanting to depend on TSLint fallback
|
|
175
|
-
],
|
|
176
|
-
},
|
|
177
|
-
]);
|
|
178
|
-
(0, utils_2.updateArrPropAndRemoveDuplication)(convertedRootESLintConfig, {
|
|
179
|
-
/**
|
|
180
|
-
* For now, extending from these is too different to what the CLI ships with today, so
|
|
181
|
-
* we remove them from the converted results. We should look to move towards extending
|
|
182
|
-
* from these once we have more influence over the generated code. We don't want users
|
|
183
|
-
* to have lint errors from OOTB generated code.
|
|
184
|
-
*/
|
|
185
|
-
extends: [
|
|
186
|
-
'plugin:@typescript-eslint/recommended',
|
|
187
|
-
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
|
188
|
-
],
|
|
189
|
-
}, 'extends', true);
|
|
190
|
-
dedupeRulesAgainstConfigs(convertedRootESLintConfig, [
|
|
191
|
-
eslintPluginConfigBase,
|
|
192
|
-
eslintPluginConfigNgCliCompat,
|
|
193
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
194
|
-
]);
|
|
195
|
-
dedupeEnvAgainstConfigs(convertedRootESLintConfig, [
|
|
196
|
-
eslintPluginConfigBase,
|
|
197
|
-
eslintPluginConfigNgCliCompat,
|
|
198
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
199
|
-
]);
|
|
200
|
-
const { codeRules, templateRules } = separateCodeAndTemplateRules(convertedRootESLintConfig);
|
|
201
|
-
(0, utils_2.updateObjPropAndRemoveDuplication)({ rules: templateRules }, eslintPluginTemplateConfigRecommended, 'rules', false);
|
|
202
|
-
convertedRootESLintConfig.root = true;
|
|
203
|
-
// Each additional project is linted independently
|
|
204
|
-
convertedRootESLintConfig.ignorePatterns = ['projects/**/*'];
|
|
205
|
-
convertedRootESLintConfig.overrides = [
|
|
206
|
-
{
|
|
207
|
-
files: ['*.ts'],
|
|
208
|
-
parserOptions: {
|
|
209
|
-
project: ['tsconfig.json', 'e2e/tsconfig.json'],
|
|
210
|
-
createDefaultProgram: true,
|
|
211
|
-
},
|
|
212
|
-
extends: [
|
|
213
|
-
'plugin:@angular-eslint/ng-cli-compat',
|
|
214
|
-
'plugin:@angular-eslint/ng-cli-compat--formatting-add-on',
|
|
215
|
-
'plugin:@angular-eslint/template/process-inline-templates',
|
|
216
|
-
...(convertedRootESLintConfig.extends || []),
|
|
217
|
-
],
|
|
218
|
-
plugins: convertedRootESLintConfig.plugins || undefined,
|
|
219
|
-
rules: codeRules,
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
files: ['*.html'],
|
|
223
|
-
extends: ['plugin:@angular-eslint/template/recommended'],
|
|
224
|
-
rules: templateRules,
|
|
225
|
-
},
|
|
226
|
-
];
|
|
227
|
-
// No longer relevant/required
|
|
228
|
-
delete convertedRootESLintConfig.parser;
|
|
229
|
-
delete convertedRootESLintConfig.parserOptions;
|
|
230
|
-
// All applied in the .ts overrides block so should no longer be at the root of the config
|
|
231
|
-
delete convertedRootESLintConfig.rules;
|
|
232
|
-
delete convertedRootESLintConfig.plugins;
|
|
233
|
-
delete convertedRootESLintConfig.extends;
|
|
234
|
-
return (0, schematics_1.chain)([
|
|
235
|
-
(0, utils_2.ensureESLintPluginsAreInstalled)(Array.from(new Set([
|
|
236
|
-
/**
|
|
237
|
-
* These three plugins are needed for the ng-cli-compat config
|
|
238
|
-
*/
|
|
239
|
-
'eslint-plugin-import',
|
|
240
|
-
'eslint-plugin-jsdoc',
|
|
241
|
-
'eslint-plugin-prefer-arrow',
|
|
242
|
-
...convertedRoot.ensureESLintPlugins,
|
|
243
|
-
]))),
|
|
244
|
-
// Create the .eslintrc.json file in the tree using the finalized config
|
|
245
|
-
(0, utils_1.updateJsonInTree)(rootESLintrcJsonPath, () => convertedRootESLintConfig),
|
|
246
|
-
]);
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
function convertNonRootTSLintConfig(schema, projectRoot, projectType, projectTSLintJsonPath, rootESLintrcJsonPath) {
|
|
250
|
-
return async (tree, context) => {
|
|
251
|
-
const rawProjectTSLintJson = (0, utils_1.readJsonInTree)(tree, projectTSLintJsonPath);
|
|
252
|
-
const rawRootESLintrcJson = (0, utils_1.readJsonInTree)(tree, rootESLintrcJsonPath);
|
|
253
|
-
const convertToESLintConfig = (0, convert_to_eslint_config_1.createConvertToESLintConfig)(context);
|
|
254
|
-
const convertedProject = await convertToESLintConfig(projectTSLintJsonPath, rawProjectTSLintJson);
|
|
255
|
-
const convertedProjectESLintConfig = convertedProject.convertedESLintConfig;
|
|
256
|
-
warnInCaseOfUnconvertedRules(context, projectTSLintJsonPath, convertedProject.unconvertedTSLintRules);
|
|
257
|
-
// We mutate these as part of the transformations, so make copies first
|
|
258
|
-
const eslintPluginConfigBase = Object.assign({}, eslintPluginConfigBaseOriginal);
|
|
259
|
-
const eslintPluginConfigNgCliCompat = Object.assign({}, eslintPluginConfigNgCliCompatOriginal);
|
|
260
|
-
const eslintPluginConfigNgCliCompatFormattingAddOn = Object.assign({}, eslintPluginConfigNgCliCompatFormattingAddOnOriginal);
|
|
261
|
-
const eslintPluginTemplateConfigRecommended = Object.assign({}, eslintPluginTemplateConfigRecommendedOriginal);
|
|
262
|
-
/**
|
|
263
|
-
* Force these 2 rules to be defined in the user's .eslintrc.json by removing
|
|
264
|
-
* them from the comparison config before deduping
|
|
265
|
-
*/
|
|
266
|
-
delete eslintPluginConfigNgCliCompat.rules['@angular-eslint/directive-selector'];
|
|
267
|
-
delete eslintPluginConfigNgCliCompat.rules['@angular-eslint/component-selector'];
|
|
268
|
-
removeUndesiredRulesFromConfig(convertedProjectESLintConfig);
|
|
269
|
-
adjustSomeRuleConfigs(convertedProjectESLintConfig);
|
|
270
|
-
handleFormattingRules(schema, context, convertedProjectESLintConfig);
|
|
271
|
-
/**
|
|
272
|
-
* To avoid users' configs being bigger and more verbose than necessary, we perform some
|
|
273
|
-
* deduplication against our underlying ng-cli-compat configuration that they will extend from,
|
|
274
|
-
* as well as the root config.
|
|
275
|
-
*/
|
|
276
|
-
dedupePluginsAgainstConfigs(convertedProjectESLintConfig, [
|
|
277
|
-
eslintPluginConfigBase,
|
|
278
|
-
eslintPluginConfigNgCliCompat,
|
|
279
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
280
|
-
{
|
|
281
|
-
plugins: [
|
|
282
|
-
'@angular-eslint/eslint-plugin',
|
|
283
|
-
'@angular-eslint/eslint-plugin-template',
|
|
284
|
-
'@typescript-eslint/tslint', // see note on not depending on not wanting to depend on TSLint fallback
|
|
285
|
-
],
|
|
286
|
-
},
|
|
287
|
-
]);
|
|
288
|
-
(0, utils_2.updateArrPropAndRemoveDuplication)(convertedProjectESLintConfig, {
|
|
289
|
-
/**
|
|
290
|
-
* For now, extending from these is too different to what the CLI ships with today, so
|
|
291
|
-
* we remove them from the converted results. We should look to move towards extending
|
|
292
|
-
* from these once we have more influence over the generated code. We don't want users
|
|
293
|
-
* to have lint errors from OOTB generated code.
|
|
294
|
-
*/
|
|
295
|
-
extends: [
|
|
296
|
-
'plugin:@typescript-eslint/recommended',
|
|
297
|
-
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
|
298
|
-
],
|
|
299
|
-
}, 'extends', true);
|
|
300
|
-
dedupeRulesAgainstConfigs(convertedProjectESLintConfig, [
|
|
301
|
-
eslintPluginConfigBase,
|
|
302
|
-
eslintPluginConfigNgCliCompat,
|
|
303
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
304
|
-
rawRootESLintrcJson,
|
|
305
|
-
]);
|
|
306
|
-
dedupeEnvAgainstConfigs(convertedProjectESLintConfig, [
|
|
307
|
-
eslintPluginConfigBase,
|
|
308
|
-
eslintPluginConfigNgCliCompat,
|
|
309
|
-
eslintPluginConfigNgCliCompatFormattingAddOn,
|
|
310
|
-
rawRootESLintrcJson,
|
|
311
|
-
]);
|
|
312
|
-
const { codeRules, templateRules } = separateCodeAndTemplateRules(convertedProjectESLintConfig);
|
|
313
|
-
(0, utils_2.updateObjPropAndRemoveDuplication)({ rules: templateRules }, eslintPluginTemplateConfigRecommended, 'rules', false);
|
|
314
|
-
const convertedExtends = convertedProjectESLintConfig.extends;
|
|
315
|
-
delete convertedProjectESLintConfig.extends;
|
|
316
|
-
// Extend from the workspace's root config at the top level
|
|
317
|
-
const relativeOffestToRootESLintrcJson = `${(0, utils_1.offsetFromRoot)(tree.root.path)}.eslintrc.json`;
|
|
318
|
-
convertedProjectESLintConfig.extends = relativeOffestToRootESLintrcJson;
|
|
319
|
-
convertedProjectESLintConfig.ignorePatterns = ['!**/*'];
|
|
320
|
-
convertedProjectESLintConfig.overrides = [
|
|
321
|
-
{
|
|
322
|
-
files: ['*.ts'],
|
|
323
|
-
parserOptions: {
|
|
324
|
-
project: (0, utils_1.setESLintProjectBasedOnProjectType)(projectRoot, projectType, true),
|
|
325
|
-
createDefaultProgram: true,
|
|
326
|
-
},
|
|
327
|
-
extends: convertedExtends || undefined,
|
|
328
|
-
plugins: convertedProjectESLintConfig.plugins || undefined,
|
|
329
|
-
rules: codeRules,
|
|
330
|
-
},
|
|
331
|
-
{
|
|
332
|
-
files: ['*.html'],
|
|
333
|
-
rules: templateRules,
|
|
334
|
-
},
|
|
335
|
-
];
|
|
336
|
-
// No longer relevant/required
|
|
337
|
-
delete convertedProjectESLintConfig.parser;
|
|
338
|
-
delete convertedProjectESLintConfig.parserOptions;
|
|
339
|
-
// All applied in the .ts overrides block so should no longer be at the root of the config
|
|
340
|
-
delete convertedProjectESLintConfig.rules;
|
|
341
|
-
delete convertedProjectESLintConfig.plugins;
|
|
342
|
-
return (0, schematics_1.chain)([
|
|
343
|
-
(0, utils_2.ensureESLintPluginsAreInstalled)(convertedProject.ensureESLintPlugins),
|
|
344
|
-
// Create the .eslintrc.json file in the tree using the finalized config
|
|
345
|
-
(0, utils_1.updateJsonInTree)((0, core_1.join)((0, core_1.normalize)(projectRoot), '.eslintrc.json'), () => convertedProjectESLintConfig),
|
|
346
|
-
// Delete the project's tslint.json, it's no longer needed
|
|
347
|
-
(host) => host.delete(projectTSLintJsonPath),
|
|
348
|
-
]);
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Remove the relative extends to the root TSLint config before converting,
|
|
353
|
-
* otherwise all the root config will be included inline in the project config.
|
|
354
|
-
*
|
|
355
|
-
* NOTE: We have to write this update to disk because part of the conversion logic
|
|
356
|
-
* executes the TSLint CLI which reads from disk - there is no equivalent API within
|
|
357
|
-
* TSLint as a library.
|
|
358
|
-
*/
|
|
359
|
-
function removeExtendsFromProjectTSLintConfigBeforeConverting(tree, projectTSLintJsonPath) {
|
|
360
|
-
return (0, utils_1.updateJsonInTree)(projectTSLintJsonPath, (json) => {
|
|
361
|
-
if (!json.extends) {
|
|
362
|
-
return json;
|
|
363
|
-
}
|
|
364
|
-
const extendsFromRoot = `${(0, utils_1.offsetFromRoot)(tree.root.path)}tslint.json`;
|
|
365
|
-
if (Array.isArray(json.extends) && json.extends.length) {
|
|
366
|
-
json.extends = json.extends.filter((ext) => ext !== extendsFromRoot);
|
|
367
|
-
}
|
|
368
|
-
if (typeof json.extends === 'string' && json.extends === extendsFromRoot) {
|
|
369
|
-
delete json.extends;
|
|
370
|
-
}
|
|
371
|
-
return json;
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Templates and source code require different ESLint config (parsers, plugins etc), so it is
|
|
376
|
-
* critical that we leverage the "overrides" capability in ESLint.
|
|
377
|
-
*
|
|
378
|
-
* We therefore need to split out rules which are intended for Angular Templates and apply them
|
|
379
|
-
* in a dedicated config block which targets HTML files.
|
|
380
|
-
*/
|
|
381
|
-
function separateCodeAndTemplateRules(convertedESLintConfig) {
|
|
382
|
-
const codeRules = convertedESLintConfig.rules || {};
|
|
383
|
-
const templateRules = {};
|
|
384
|
-
Object.keys(codeRules).forEach((ruleName) => {
|
|
385
|
-
if (ruleName.startsWith('@angular-eslint/template') ||
|
|
386
|
-
ruleName.startsWith('@angular-eslint/eslint-plugin-template')) {
|
|
387
|
-
templateRules[ruleName] = codeRules[ruleName];
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
Object.keys(templateRules).forEach((ruleName) => {
|
|
391
|
-
delete codeRules[ruleName];
|
|
392
|
-
});
|
|
393
|
-
return {
|
|
394
|
-
codeRules,
|
|
395
|
-
templateRules,
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
function handleFormattingRules(schema, context, convertedConfig) {
|
|
399
|
-
if (!convertedConfig.rules) {
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
if (!schema.convertIndentationRules) {
|
|
403
|
-
delete convertedConfig.rules['@typescript-eslint/indent'];
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* We really don't want to encourage the practice of using a linter
|
|
408
|
-
* for formatting concerns. Please use prettier y'all!
|
|
409
|
-
*/
|
|
410
|
-
if (convertedConfig.rules['@typescript-eslint/indent']) {
|
|
411
|
-
context.logger.warn(`\nWARNING: You are currently using a linting rule to deal with indentation. Linters are not well suited to purely code formatting concerns, such as indentation.`);
|
|
412
|
-
context.logger.warn('\nPer your instructions we have migrated your TSLint indentation configuration to its equivalent in ESLint, but we strongly recommend switching to a dedicated code formatter such as https://prettier.io\n');
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
function adjustSomeRuleConfigs(convertedConfig) {
|
|
416
|
-
if (!convertedConfig.rules) {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Adjust the quotes rule to always add allowTemplateLiterals as it is most common and can
|
|
421
|
-
* always be removed by the user if undesired in their case.
|
|
422
|
-
*/
|
|
423
|
-
if (convertedConfig.rules['@typescript-eslint/quotes']) {
|
|
424
|
-
if (!Array.isArray(convertedConfig.rules['@typescript-eslint/quotes'])) {
|
|
425
|
-
convertedConfig.rules['@typescript-eslint/quotes'] = [
|
|
426
|
-
convertedConfig.rules['@typescript-eslint/quotes'],
|
|
427
|
-
'single',
|
|
428
|
-
];
|
|
429
|
-
}
|
|
430
|
-
if (!convertedConfig.rules['@typescript-eslint/quotes'][2]) {
|
|
431
|
-
convertedConfig.rules['@typescript-eslint/quotes'].push({
|
|
432
|
-
allowTemplateLiterals: true,
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
function removeUndesiredRulesFromConfig(convertedConfig) {
|
|
438
|
-
if (!convertedConfig.rules) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
delete convertedConfig.rules['@typescript-eslint/tslint/config'];
|
|
442
|
-
/**
|
|
443
|
-
* BOTH OF THESE RULES CREATE A LOT OF NOISE ON OOTB POLYFILLS.TS
|
|
444
|
-
*/
|
|
445
|
-
// WAS -> "spaced-comment": [
|
|
446
|
-
// "error",
|
|
447
|
-
// "always",
|
|
448
|
-
// {
|
|
449
|
-
// "markers": ["/"]
|
|
450
|
-
// }
|
|
451
|
-
// ],
|
|
452
|
-
delete convertedConfig.rules['spaced-comment'];
|
|
453
|
-
// WAS -> "jsdoc/check-indentation": "error",
|
|
454
|
-
delete convertedConfig.rules['jsdoc/check-indentation'];
|
|
455
|
-
/**
|
|
456
|
-
* We want to use these ones differently (with different rule config) to how they
|
|
457
|
-
* are converted. Because they exist with different config, they wouldn't be cleaned
|
|
458
|
-
* up by our deduplication logic and we have to manually remove them.
|
|
459
|
-
*/
|
|
460
|
-
delete convertedConfig.rules['no-restricted-imports'];
|
|
461
|
-
/**
|
|
462
|
-
* We have handled this in eslint-plugin ng-cli-compat.json, any subtle differences that would
|
|
463
|
-
* cause the deduplication logic not to find a match can be addressed via PRs to the ng-cli-compat
|
|
464
|
-
* config in the plugin.
|
|
465
|
-
*/
|
|
466
|
-
delete convertedConfig.rules['no-console'];
|
|
467
|
-
}
|
|
468
|
-
function dedupeEnvAgainstConfigs(convertedConfig, otherConfigs) {
|
|
469
|
-
otherConfigs.forEach((againstConfig) => {
|
|
470
|
-
(0, utils_2.updateObjPropAndRemoveDuplication)(convertedConfig, againstConfig, 'env', true);
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
function dedupeRulesAgainstConfigs(convertedConfig, otherConfigs) {
|
|
474
|
-
otherConfigs.forEach((againstConfig) => {
|
|
475
|
-
(0, utils_2.updateObjPropAndRemoveDuplication)(convertedConfig, againstConfig, 'rules', false);
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
function dedupePluginsAgainstConfigs(convertedConfig, otherConfigs) {
|
|
479
|
-
otherConfigs.forEach((againstConfig) => {
|
|
480
|
-
(0, utils_2.updateArrPropAndRemoveDuplication)(convertedConfig, againstConfig, 'plugins', true);
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* We don't want the user to depend on the TSLint fallback plugin, we will instead
|
|
485
|
-
* explicitly inform them of the rules that could not be converted automatically and
|
|
486
|
-
* advise them on what to do next.
|
|
487
|
-
*/
|
|
488
|
-
function warnInCaseOfUnconvertedRules(context, tslintConfigPath, unconvertedTSLintRules) {
|
|
489
|
-
/*
|
|
490
|
-
* The following rules are known to be missing from the Angular CLI equivalent TSLint
|
|
491
|
-
* setup, so they will be part of our convertedRoot data:
|
|
492
|
-
*
|
|
493
|
-
* // FORMATTING! Please use prettier y'all!
|
|
494
|
-
* "import-spacing": true
|
|
495
|
-
*
|
|
496
|
-
* // POSSIBLY NOT REQUIRED - typescript-eslint provides explicit-function-return-type (not yet enabled)
|
|
497
|
-
* "typedef": [
|
|
498
|
-
* true,
|
|
499
|
-
* "call-signature",
|
|
500
|
-
* ]
|
|
501
|
-
*
|
|
502
|
-
* // FORMATTING! Please use prettier y'all!
|
|
503
|
-
* "whitespace": [
|
|
504
|
-
* true,
|
|
505
|
-
* "check-branch",
|
|
506
|
-
* "check-decl",
|
|
507
|
-
* "check-operator",
|
|
508
|
-
* "check-separator",
|
|
509
|
-
* "check-type",
|
|
510
|
-
* "check-typecast",
|
|
511
|
-
* ]
|
|
512
|
-
*/
|
|
513
|
-
const unconvertedTSLintRuleNames = unconvertedTSLintRules
|
|
514
|
-
.filter((unconverted) => !['import-spacing', 'whitespace', 'typedef'].includes(unconverted.ruleName))
|
|
515
|
-
.map((unconverted) => unconverted.ruleName);
|
|
516
|
-
if (unconvertedTSLintRuleNames.length > 0) {
|
|
517
|
-
context.logger.warn(`\nWARNING: Within "${tslintConfigPath}", the following ${unconvertedTSLintRuleNames.length} rule(s) did not have known converters in https://github.com/typescript-eslint/tslint-to-eslint-config`);
|
|
518
|
-
context.logger.warn('\n - ' + unconvertedTSLintRuleNames.join('\n - '));
|
|
519
|
-
context.logger.warn('\nYou will need to decide on how to handle the above manually, but everything else has been handled for you automatically.\n');
|
|
520
|
-
}
|
|
521
|
-
}
|
|
13
|
+
exports.default = default_1;
|