@depup/angular-eslint__eslint-plugin 21.3.1-depup.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/LICENSE +21 -0
- package/README.md +31 -0
- package/changes.json +10 -0
- package/dist/configs/README.md +44 -0
- package/dist/configs/all.json +54 -0
- package/dist/configs/recommended.json +18 -0
- package/dist/index.d.ts +233 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +145 -0
- package/dist/rules/component-class-suffix.d.ts +15 -0
- package/dist/rules/component-class-suffix.d.ts.map +1 -0
- package/dist/rules/component-class-suffix.js +56 -0
- package/dist/rules/component-max-inline-declarations.d.ts +17 -0
- package/dist/rules/component-max-inline-declarations.d.ts.map +1 -0
- package/dist/rules/component-max-inline-declarations.js +107 -0
- package/dist/rules/component-selector.d.ts +14 -0
- package/dist/rules/component-selector.d.ts.map +1 -0
- package/dist/rules/component-selector.js +218 -0
- package/dist/rules/computed-must-return.d.ts +11 -0
- package/dist/rules/computed-must-return.d.ts.map +1 -0
- package/dist/rules/computed-must-return.js +62 -0
- package/dist/rules/consistent-component-styles.d.ts +12 -0
- package/dist/rules/consistent-component-styles.d.ts.map +1 -0
- package/dist/rules/consistent-component-styles.js +97 -0
- package/dist/rules/contextual-decorator.d.ts +12 -0
- package/dist/rules/contextual-decorator.d.ts.map +1 -0
- package/dist/rules/contextual-decorator.js +61 -0
- package/dist/rules/contextual-lifecycle.d.ts +11 -0
- package/dist/rules/contextual-lifecycle.d.ts.map +1 -0
- package/dist/rules/contextual-lifecycle.js +61 -0
- package/dist/rules/directive-class-suffix.d.ts +13 -0
- package/dist/rules/directive-class-suffix.d.ts.map +1 -0
- package/dist/rules/directive-class-suffix.js +60 -0
- package/dist/rules/directive-selector.d.ts +14 -0
- package/dist/rules/directive-selector.d.ts.map +1 -0
- package/dist/rules/directive-selector.js +156 -0
- package/dist/rules/no-async-lifecycle-method.d.ts +11 -0
- package/dist/rules/no-async-lifecycle-method.d.ts.map +1 -0
- package/dist/rules/no-async-lifecycle-method.js +45 -0
- package/dist/rules/no-attribute-decorator.d.ts +11 -0
- package/dist/rules/no-attribute-decorator.d.ts.map +1 -0
- package/dist/rules/no-attribute-decorator.js +32 -0
- package/dist/rules/no-conflicting-lifecycle.d.ts +11 -0
- package/dist/rules/no-conflicting-lifecycle.d.ts.map +1 -0
- package/dist/rules/no-conflicting-lifecycle.js +74 -0
- package/dist/rules/no-developer-preview.d.ts +11 -0
- package/dist/rules/no-developer-preview.d.ts.map +1 -0
- package/dist/rules/no-developer-preview.js +45 -0
- package/dist/rules/no-duplicates-in-metadata-arrays.d.ts +11 -0
- package/dist/rules/no-duplicates-in-metadata-arrays.d.ts.map +1 -0
- package/dist/rules/no-duplicates-in-metadata-arrays.js +67 -0
- package/dist/rules/no-empty-lifecycle-method.d.ts +11 -0
- package/dist/rules/no-empty-lifecycle-method.d.ts.map +1 -0
- package/dist/rules/no-empty-lifecycle-method.js +75 -0
- package/dist/rules/no-experimental.d.ts +11 -0
- package/dist/rules/no-experimental.d.ts.map +1 -0
- package/dist/rules/no-experimental.js +45 -0
- package/dist/rules/no-forward-ref.d.ts +12 -0
- package/dist/rules/no-forward-ref.d.ts.map +1 -0
- package/dist/rules/no-forward-ref.js +33 -0
- package/dist/rules/no-implicit-take-until-destroyed.d.ts +11 -0
- package/dist/rules/no-implicit-take-until-destroyed.d.ts.map +1 -0
- package/dist/rules/no-implicit-take-until-destroyed.js +83 -0
- package/dist/rules/no-input-prefix.d.ts +13 -0
- package/dist/rules/no-input-prefix.d.ts.map +1 -0
- package/dist/rules/no-input-prefix.js +118 -0
- package/dist/rules/no-input-rename.d.ts +13 -0
- package/dist/rules/no-input-rename.d.ts.map +1 -0
- package/dist/rules/no-input-rename.js +213 -0
- package/dist/rules/no-inputs-metadata-property.d.ts +11 -0
- package/dist/rules/no-inputs-metadata-property.d.ts.map +1 -0
- package/dist/rules/no-inputs-metadata-property.js +53 -0
- package/dist/rules/no-lifecycle-call.d.ts +11 -0
- package/dist/rules/no-lifecycle-call.d.ts.map +1 -0
- package/dist/rules/no-lifecycle-call.js +49 -0
- package/dist/rules/no-output-native.d.ts +11 -0
- package/dist/rules/no-output-native.d.ts.map +1 -0
- package/dist/rules/no-output-native.js +47 -0
- package/dist/rules/no-output-on-prefix.d.ts +11 -0
- package/dist/rules/no-output-on-prefix.d.ts.map +1 -0
- package/dist/rules/no-output-on-prefix.js +48 -0
- package/dist/rules/no-output-rename.d.ts +11 -0
- package/dist/rules/no-output-rename.d.ts.map +1 -0
- package/dist/rules/no-output-rename.js +172 -0
- package/dist/rules/no-outputs-metadata-property.d.ts +11 -0
- package/dist/rules/no-outputs-metadata-property.d.ts.map +1 -0
- package/dist/rules/no-outputs-metadata-property.js +53 -0
- package/dist/rules/no-pipe-impure.d.ts +11 -0
- package/dist/rules/no-pipe-impure.d.ts.map +1 -0
- package/dist/rules/no-pipe-impure.js +42 -0
- package/dist/rules/no-queries-metadata-property.d.ts +11 -0
- package/dist/rules/no-queries-metadata-property.d.ts.map +1 -0
- package/dist/rules/no-queries-metadata-property.js +38 -0
- package/dist/rules/no-uncalled-signals.d.ts +12 -0
- package/dist/rules/no-uncalled-signals.d.ts.map +1 -0
- package/dist/rules/no-uncalled-signals.js +92 -0
- package/dist/rules/pipe-prefix.d.ts +15 -0
- package/dist/rules/pipe-prefix.d.ts.map +1 -0
- package/dist/rules/pipe-prefix.js +92 -0
- package/dist/rules/prefer-host-metadata-property.d.ts +10 -0
- package/dist/rules/prefer-host-metadata-property.d.ts.map +1 -0
- package/dist/rules/prefer-host-metadata-property.js +40 -0
- package/dist/rules/prefer-inject.d.ts +11 -0
- package/dist/rules/prefer-inject.d.ts.map +1 -0
- package/dist/rules/prefer-inject.js +86 -0
- package/dist/rules/prefer-on-push-component-change-detection.d.ts +11 -0
- package/dist/rules/prefer-on-push-component-change-detection.d.ts.map +1 -0
- package/dist/rules/prefer-on-push-component-change-detection.js +81 -0
- package/dist/rules/prefer-output-emitter-ref.d.ts +10 -0
- package/dist/rules/prefer-output-emitter-ref.d.ts.map +1 -0
- package/dist/rules/prefer-output-emitter-ref.js +30 -0
- package/dist/rules/prefer-output-readonly.d.ts +11 -0
- package/dist/rules/prefer-output-readonly.d.ts.map +1 -0
- package/dist/rules/prefer-output-readonly.js +51 -0
- package/dist/rules/prefer-signal-model.d.ts +10 -0
- package/dist/rules/prefer-signal-model.d.ts.map +1 -0
- package/dist/rules/prefer-signal-model.js +71 -0
- package/dist/rules/prefer-signals.d.ts +20 -0
- package/dist/rules/prefer-signals.d.ts.map +1 -0
- package/dist/rules/prefer-signals.js +174 -0
- package/dist/rules/prefer-standalone.d.ts +11 -0
- package/dist/rules/prefer-standalone.d.ts.map +1 -0
- package/dist/rules/prefer-standalone.js +66 -0
- package/dist/rules/relative-url-prefix.d.ts +11 -0
- package/dist/rules/relative-url-prefix.d.ts.map +1 -0
- package/dist/rules/relative-url-prefix.js +59 -0
- package/dist/rules/require-lifecycle-on-prototype.d.ts +11 -0
- package/dist/rules/require-lifecycle-on-prototype.d.ts.map +1 -0
- package/dist/rules/require-lifecycle-on-prototype.js +72 -0
- package/dist/rules/require-localize-metadata.d.ts +17 -0
- package/dist/rules/require-localize-metadata.d.ts.map +1 -0
- package/dist/rules/require-localize-metadata.js +123 -0
- package/dist/rules/runtime-localize.d.ts +11 -0
- package/dist/rules/runtime-localize.d.ts.map +1 -0
- package/dist/rules/runtime-localize.js +45 -0
- package/dist/rules/sort-keys-in-type-decorator.d.ts +16 -0
- package/dist/rules/sort-keys-in-type-decorator.d.ts.map +1 -0
- package/dist/rules/sort-keys-in-type-decorator.js +191 -0
- package/dist/rules/sort-lifecycle-methods.d.ts +11 -0
- package/dist/rules/sort-lifecycle-methods.d.ts.map +1 -0
- package/dist/rules/sort-lifecycle-methods.js +45 -0
- package/dist/rules/use-component-selector.d.ts +11 -0
- package/dist/rules/use-component-selector.d.ts.map +1 -0
- package/dist/rules/use-component-selector.js +41 -0
- package/dist/rules/use-component-view-encapsulation.d.ts +11 -0
- package/dist/rules/use-component-view-encapsulation.d.ts.map +1 -0
- package/dist/rules/use-component-view-encapsulation.js +49 -0
- package/dist/rules/use-injectable-provided-in.d.ts +13 -0
- package/dist/rules/use-injectable-provided-in.d.ts.map +1 -0
- package/dist/rules/use-injectable-provided-in.js +63 -0
- package/dist/rules/use-lifecycle-interface.d.ts +11 -0
- package/dist/rules/use-lifecycle-interface.d.ts.map +1 -0
- package/dist/rules/use-lifecycle-interface.js +65 -0
- package/dist/rules/use-pipe-transform-interface.d.ts +11 -0
- package/dist/rules/use-pipe-transform-interface.d.ts.map +1 -0
- package/dist/rules/use-pipe-transform-interface.js +49 -0
- package/dist/utils/create-eslint-rule.d.ts +8 -0
- package/dist/utils/create-eslint-rule.d.ts.map +1 -0
- package/dist/utils/create-eslint-rule.js +28 -0
- package/dist/utils/jsdoc.d.ts +11 -0
- package/dist/utils/jsdoc.d.ts.map +1 -0
- package/dist/utils/jsdoc.js +174 -0
- package/dist/utils/signals.d.ts +2 -0
- package/dist/utils/signals.d.ts.map +1 -0
- package/dist/utils/signals.js +10 -0
- package/package.json +56 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
5
|
+
const eslint_utils_1 = require("@typescript-eslint/utils/eslint-utils");
|
|
6
|
+
const jsdoc_1 = require("../utils/jsdoc");
|
|
7
|
+
exports.RULE_NAME = 'no-developer-preview';
|
|
8
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
9
|
+
name: exports.RULE_NAME,
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: `Disallow using code which is marked as developer preview`,
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
noDeveloperPreview: '`{{name}}` is in developer preview',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const services = (0, eslint_utils_1.getParserServices)(context);
|
|
23
|
+
const checker = services.program.getTypeChecker();
|
|
24
|
+
return {
|
|
25
|
+
Identifier: (node) => {
|
|
26
|
+
if ((0, jsdoc_1.isDeclaration)(node) || (0, jsdoc_1.isInsideExportOrImport)(node)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const symbols = (0, jsdoc_1.getSymbols)(node, services, checker);
|
|
30
|
+
if (!(0, jsdoc_1.hasJsDocTag)(symbols, 'developerPreview')) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const { name } = node;
|
|
34
|
+
context.report({
|
|
35
|
+
node,
|
|
36
|
+
messageId: 'noDeveloperPreview',
|
|
37
|
+
data: { name },
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
44
|
+
rationale: `Angular's [developer preview APIs](https://angular.dev/reference/releases#developer-preview) are fully functional and polished, but not yet covered by Angular's [breaking change policy](https://angular.dev/reference/releases#breaking-change-policy-and-update-paths). These APIs may change even in patch releases, making them risky for production applications.`,
|
|
45
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'noDuplicatesInMetadataArrays';
|
|
3
|
+
export declare const RULE_NAME = "no-duplicates-in-metadata-arrays";
|
|
4
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noDuplicatesInMetadataArrays", [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
9
|
+
rationale: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=no-duplicates-in-metadata-arrays.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-duplicates-in-metadata-arrays.d.ts","sourceRoot":"","sources":["../../src/rules/no-duplicates-in-metadata-arrays.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,8BAA8B,CAAC;AACxD,eAAO,MAAM,SAAS,qCAAqC,CAAC;;;;AAE5D,wBA4CG;AAoBH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const utils_1 = require("@angular-eslint/utils");
|
|
5
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
6
|
+
const utils_2 = require("@typescript-eslint/utils");
|
|
7
|
+
exports.RULE_NAME = 'no-duplicates-in-metadata-arrays';
|
|
8
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
9
|
+
name: exports.RULE_NAME,
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'suggestion',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Ensures that metadata arrays do not contain duplicate entries.',
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
noDuplicatesInMetadataArrays: 'Entry is duplicated in metadata array',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const selectors = [
|
|
23
|
+
// https://angular.dev/api/core/NgModule
|
|
24
|
+
`${utils_1.Selectors.MODULE_CLASS_DECORATOR} Property[key.name=${(0, utils_1.toPattern)([
|
|
25
|
+
'providers',
|
|
26
|
+
'declarations',
|
|
27
|
+
'imports',
|
|
28
|
+
'exports',
|
|
29
|
+
])}] > ArrayExpression`,
|
|
30
|
+
// https://angular.dev/api/core/Component
|
|
31
|
+
`${utils_1.Selectors.COMPONENT_CLASS_DECORATOR} Property[key.name=${(0, utils_1.toPattern)([
|
|
32
|
+
'imports',
|
|
33
|
+
])}] > ArrayExpression`,
|
|
34
|
+
// https://angular.dev/api/core/Directive
|
|
35
|
+
`${utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR} Property[key.name=${(0, utils_1.toPattern)([
|
|
36
|
+
'providers',
|
|
37
|
+
])}] > ArrayExpression`,
|
|
38
|
+
].join(',');
|
|
39
|
+
return {
|
|
40
|
+
[selectors]({ elements }) {
|
|
41
|
+
getDuplicateItems(elements).forEach((duplicateImport) => {
|
|
42
|
+
context.report({
|
|
43
|
+
node: duplicateImport,
|
|
44
|
+
messageId: 'noDuplicatesInMetadataArrays',
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
function getDuplicateItems(elements) {
|
|
52
|
+
const items = elements.filter(utils_2.ASTUtils.isIdentifier);
|
|
53
|
+
const uniqueItemNames = new Set();
|
|
54
|
+
const duplicateItems = [];
|
|
55
|
+
items.forEach((item) => {
|
|
56
|
+
if (uniqueItemNames.has(item.name)) {
|
|
57
|
+
duplicateItems.push(item);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
uniqueItemNames.add(item.name);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return duplicateItems;
|
|
64
|
+
}
|
|
65
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
66
|
+
rationale: 'Duplicate entries in Angular metadata arrays like providers, imports, declarations, or exports serve no purpose and indicate a mistake. When the same provider is listed twice in a providers array, Angular will create it twice, potentially leading to unexpected behavior with singleton services. Duplicate imports or declarations simply waste bundle size and make the metadata harder to read. These duplicates typically occur from copy-paste errors, merge conflicts, or refactoring mistakes. Catching these duplicates early prevents subtle bugs and keeps module metadata clean and understandable.',
|
|
67
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'noEmptyLifecycleMethod' | 'suggestRemoveLifecycleMethod';
|
|
3
|
+
export declare const RULE_NAME = "no-empty-lifecycle-method";
|
|
4
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
9
|
+
rationale: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=no-empty-lifecycle-method.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-empty-lifecycle-method.d.ts","sourceRoot":"","sources":["../../src/rules/no-empty-lifecycle-method.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAClB,wBAAwB,GACxB,8BAA8B,CAAC;AACnC,eAAO,MAAM,SAAS,8BAA8B,CAAC;;;;AAErD,wBAsFG;AAYH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const utils_1 = require("@angular-eslint/utils");
|
|
5
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
6
|
+
exports.RULE_NAME = 'no-empty-lifecycle-method';
|
|
7
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
8
|
+
name: exports.RULE_NAME,
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Disallows declaring empty lifecycle methods',
|
|
13
|
+
recommended: 'recommended',
|
|
14
|
+
},
|
|
15
|
+
hasSuggestions: true,
|
|
16
|
+
schema: [],
|
|
17
|
+
messages: {
|
|
18
|
+
noEmptyLifecycleMethod: 'Lifecycle methods should not be empty',
|
|
19
|
+
suggestRemoveLifecycleMethod: 'Remove lifecycle method',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
const sourceCode = context.sourceCode;
|
|
25
|
+
const angularDecoratorsPattern = (0, utils_1.toPattern)([
|
|
26
|
+
'Component',
|
|
27
|
+
'Directive',
|
|
28
|
+
'Injectable',
|
|
29
|
+
'NgModule',
|
|
30
|
+
'Pipe',
|
|
31
|
+
]);
|
|
32
|
+
const angularLifecycleMethodsPattern = (0, utils_1.toPattern)([
|
|
33
|
+
...utils_1.ASTUtils.ANGULAR_LIFECYCLE_METHODS,
|
|
34
|
+
]);
|
|
35
|
+
return {
|
|
36
|
+
[`${utils_1.Selectors.decoratorDefinition(angularDecoratorsPattern)} > ClassBody > ${utils_1.Selectors.methodDefinition(angularLifecycleMethodsPattern)}[value.body.body.length=0]`](node) {
|
|
37
|
+
context.report({
|
|
38
|
+
node,
|
|
39
|
+
messageId: 'noEmptyLifecycleMethod',
|
|
40
|
+
suggest: [
|
|
41
|
+
{
|
|
42
|
+
messageId: 'suggestRemoveLifecycleMethod',
|
|
43
|
+
fix: (fixer) => {
|
|
44
|
+
const importDeclarations = utils_1.ASTUtils.getImportDeclarations(node, '@angular/core') ?? [];
|
|
45
|
+
const interfaceName = utils_1.ASTUtils.getRawText(node).replace(/^ng+/, '');
|
|
46
|
+
const text = sourceCode.getText();
|
|
47
|
+
const totalInterfaceOccurrences = getTotalInterfaceOccurrences(text, interfaceName);
|
|
48
|
+
const totalInterfaceOccurrencesSafeForRemoval = 2;
|
|
49
|
+
return [
|
|
50
|
+
fixer.remove(node),
|
|
51
|
+
utils_1.RuleFixes.getImplementsRemoveFix(sourceCode, node.parent.parent, interfaceName, fixer),
|
|
52
|
+
totalInterfaceOccurrences <=
|
|
53
|
+
totalInterfaceOccurrencesSafeForRemoval
|
|
54
|
+
? utils_1.RuleFixes.getImportRemoveFix(sourceCode, importDeclarations, interfaceName, fixer)
|
|
55
|
+
: null,
|
|
56
|
+
].filter(utils_1.isNotNullOrUndefined);
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
function stripSpecialCharacters(text) {
|
|
66
|
+
return text.replace(/[\W]/g, '');
|
|
67
|
+
}
|
|
68
|
+
function getTotalInterfaceOccurrences(text, interfaceName) {
|
|
69
|
+
return text
|
|
70
|
+
.split(' ')
|
|
71
|
+
.filter((item) => stripSpecialCharacters(item) === interfaceName).length;
|
|
72
|
+
}
|
|
73
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
74
|
+
rationale: 'Empty lifecycle methods add noise to the codebase without providing any value. When a developer sees ngOnInit(), ngOnDestroy(), or other lifecycle hooks, they expect to find important initialization, cleanup, or other lifecycle-related logic. Finding an empty method wastes time during code review and maintenance. Empty lifecycle methods often remain after code has been refactored or removed, serving as dead code that clutters the component. They also require unnecessary imports of lifecycle interfaces (like OnInit, OnDestroy). Removing empty lifecycle methods makes components cleaner, easier to understand, and reduces the file size.',
|
|
75
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'noExperimental';
|
|
3
|
+
export declare const RULE_NAME = "no-experimental";
|
|
4
|
+
declare const _default: import("@typescript-eslint/utils/eslint-utils").RuleModule<"noExperimental", [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/eslint-utils").RuleListener> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
9
|
+
rationale: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=no-experimental.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-experimental.d.ts","sourceRoot":"","sources":["../../src/rules/no-experimental.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAC1C,eAAO,MAAM,SAAS,oBAAoB,CAAC;;;;AAE3C,wBAsCG;AAEH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
5
|
+
const eslint_utils_1 = require("@typescript-eslint/utils/eslint-utils");
|
|
6
|
+
const jsdoc_1 = require("../utils/jsdoc");
|
|
7
|
+
exports.RULE_NAME = 'no-experimental';
|
|
8
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
9
|
+
name: exports.RULE_NAME,
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: `Disallow using code which is marked as experimental`,
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
noExperimental: '`{{name}}` is experimental',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const services = (0, eslint_utils_1.getParserServices)(context);
|
|
23
|
+
const checker = services.program.getTypeChecker();
|
|
24
|
+
return {
|
|
25
|
+
Identifier: (node) => {
|
|
26
|
+
if ((0, jsdoc_1.isDeclaration)(node) || (0, jsdoc_1.isInsideExportOrImport)(node)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const symbols = (0, jsdoc_1.getSymbols)(node, services, checker);
|
|
30
|
+
if (!(0, jsdoc_1.hasJsDocTag)(symbols, 'experimental')) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const { name } = node;
|
|
34
|
+
context.report({
|
|
35
|
+
node,
|
|
36
|
+
messageId: 'noExperimental',
|
|
37
|
+
data: { name },
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
44
|
+
rationale: `Angular's [experimental APIs](https://angular.dev/reference/releases#experimental) are subject to significant changes or removal without notice and are not covered by Angular's [breaking change policy](https://angular.dev/reference/releases#breaking-change-policy-and-update-paths). These APIs may change even in patch releases, making them risky for production applications.`,
|
|
45
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'noForwardRef';
|
|
3
|
+
export declare const RULE_NAME = "no-forward-ref";
|
|
4
|
+
export declare const FORWARD_REF = "forwardRef";
|
|
5
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noForwardRef", [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
9
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
10
|
+
rationale: string;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=no-forward-ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-forward-ref.d.ts","sourceRoot":"","sources":["../../src/rules/no-forward-ref.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC;AACxC,eAAO,MAAM,SAAS,mBAAmB,CAAC;AAE1C,eAAO,MAAM,WAAW,eAAe,CAAC;;;;AAExC,wBAyBG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.FORWARD_REF = exports.RULE_NAME = void 0;
|
|
4
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
5
|
+
exports.RULE_NAME = 'no-forward-ref';
|
|
6
|
+
exports.FORWARD_REF = 'forwardRef';
|
|
7
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
8
|
+
name: exports.RULE_NAME,
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
docs: {
|
|
12
|
+
description: `Disallows usage of \`${exports.FORWARD_REF}\` references for DI`,
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
messages: {
|
|
16
|
+
noForwardRef: `Avoid using \`${exports.FORWARD_REF}\``,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
[`CallExpression[callee.type="Identifier"][callee.name="${exports.FORWARD_REF}"]`](node) {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId: 'noForwardRef',
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
32
|
+
rationale: "The forwardRef() function is a workaround for circular dependencies in Angular's dependency injection system, but it obscures the dependency graph and can make code harder to understand and maintain. When forwardRef() is used, it's often a sign of poor architecture, such as circular dependencies between components or services that could be resolved through better abstraction. Modern Angular and TypeScript have reduced the need for forwardRef() in most cases. Instead, consider restructuring your code to eliminate circular dependencies, using interfaces for dependency injection, or moving shared logic into a separate service.",
|
|
33
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'noImplicitTakeUntilDestroyed';
|
|
3
|
+
export declare const RULE_NAME = "no-implicit-take-until-destroyed";
|
|
4
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noImplicitTakeUntilDestroyed", [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
9
|
+
rationale: string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=no-implicit-take-until-destroyed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-implicit-take-until-destroyed.d.ts","sourceRoot":"","sources":["../../src/rules/no-implicit-take-until-destroyed.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,8BAA8B,CAAC;AACxD,eAAO,MAAM,SAAS,qCAAqC,CAAC;;;;AAO5D,wBAgCG;AAqEH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const utils_1 = require("@angular-eslint/utils");
|
|
5
|
+
const utils_2 = require("@typescript-eslint/utils");
|
|
6
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
7
|
+
exports.RULE_NAME = 'no-implicit-take-until-destroyed';
|
|
8
|
+
const RXJS_INTEROP_LINK = 'https://angular.dev/ecosystem/rxjs-interop/take-until-destroyed';
|
|
9
|
+
const DEPENDENCY_INJECTION_CONTEXT = 'https://angular.dev/guide/di/dependency-injection-context';
|
|
10
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
11
|
+
name: exports.RULE_NAME,
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: {
|
|
15
|
+
description: `Ensures that \`takeUntilDestroyed()\` is called with an explicit \`DestroyRef\` when used outside of an injection context`,
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
messages: {
|
|
19
|
+
noImplicitTakeUntilDestroyed: `\`takeUntilDestroyed()\` must be called with an explicit \`DestroyRef\` parameter when used outside of an injection context. See more at ${DEPENDENCY_INJECTION_CONTEXT} and ${RXJS_INTEROP_LINK}`,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
return {
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
if (node.callee.type !== utils_2.AST_NODE_TYPES.Identifier ||
|
|
27
|
+
node.callee.name !== 'takeUntilDestroyed' ||
|
|
28
|
+
node.arguments.length > 0 ||
|
|
29
|
+
isInInjectionContext(node)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
context.report({
|
|
33
|
+
node,
|
|
34
|
+
messageId: 'noImplicitTakeUntilDestroyed',
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
function isInInjectionContext(node) {
|
|
41
|
+
let current = node;
|
|
42
|
+
while (current) {
|
|
43
|
+
if (isInFactoryFunction(current)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (utils_1.ASTUtils.isPropertyDefinition(current) ||
|
|
47
|
+
isConstructorMethod(current)) {
|
|
48
|
+
const classDeclaration = utils_1.ASTUtils.getNearestNodeFrom(current, utils_1.ASTUtils.isClassDeclaration);
|
|
49
|
+
if (!classDeclaration) {
|
|
50
|
+
current = current.parent;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const decorator = utils_1.ASTUtils.getAngularClassDecorator(classDeclaration);
|
|
54
|
+
if (decorator && decorator !== 'NgModule') {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
current = current.parent;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
function isConstructorMethod(node) {
|
|
63
|
+
return (node.type === utils_2.AST_NODE_TYPES.MethodDefinition && node.kind === 'constructor');
|
|
64
|
+
}
|
|
65
|
+
function isInFactoryFunction(node) {
|
|
66
|
+
if (node.type !== utils_2.AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
67
|
+
node.type !== utils_2.AST_NODE_TYPES.FunctionExpression) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const parent = node.parent;
|
|
71
|
+
if (!utils_1.ASTUtils.isProperty(parent)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const key = parent.key;
|
|
75
|
+
if (key.type === utils_2.AST_NODE_TYPES.Identifier &&
|
|
76
|
+
['factory', 'useFactory'].includes(key.name)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
82
|
+
rationale: `The \`takeUntilDestroyed()\` operator can automatically infer the current component's or directive's \`DestroyRef\` only when called within an injection context — specifically in constructors or field initializers of classes decorated with \`@Component\`, \`@Directive\`, \`@Injectable\`, or \`@Pipe\`, or in factory functions (\`useFactory\` in providers or \`factory\` in InjectionTokens). When used in lifecycle methods like \`ngOnInit()\` or \`ngAfterViewInit()\`, in regular methods, in constructors of plain classes not managed by Angular's DI system, or in \`@NgModule\` classes (which don't support the \`ngOnDestroy\` lifecycle), the injection context is not available, and \`takeUntilDestroyed()\` will throw a runtime error: "NG0203: inject() must be called from an injection context." To fix this, inject \`DestroyRef\` using \`inject(DestroyRef)\` and pass it explicitly: \`takeUntilDestroyed(this.destroyRef)\`.`,
|
|
83
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Options = [{
|
|
2
|
+
readonly prefixes: readonly string[];
|
|
3
|
+
}];
|
|
4
|
+
export type MessageIds = 'noInputPrefix';
|
|
5
|
+
export declare const RULE_NAME = "no-input-prefix";
|
|
6
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noInputPrefix", Options, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
10
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
11
|
+
rationale: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=no-input-prefix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-input-prefix.d.ts","sourceRoot":"","sources":["../../src/rules/no-input-prefix.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,OAAO,GAAG,CAAC;IAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AACjE,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC;AACzC,eAAO,MAAM,SAAS,oBAAoB,CAAC;;;;AAE3C,wBAwIG;AAWH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
|
|
4
|
+
const utils_1 = require("@angular-eslint/utils");
|
|
5
|
+
const utils_2 = require("@typescript-eslint/utils");
|
|
6
|
+
const create_eslint_rule_1 = require("../utils/create-eslint-rule");
|
|
7
|
+
exports.RULE_NAME = 'no-input-prefix';
|
|
8
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
9
|
+
name: exports.RULE_NAME,
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'suggestion',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Ensures that input bindings, including aliases, are not named or prefixed by the configured disallowed prefixes',
|
|
14
|
+
},
|
|
15
|
+
schema: [
|
|
16
|
+
{
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
prefixes: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
messages: {
|
|
30
|
+
noInputPrefix: 'Input bindings, including aliases, should not be named, nor prefixed by {{prefixes}}',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
defaultOptions: [{ prefixes: [] }],
|
|
34
|
+
create(context, [{ prefixes }]) {
|
|
35
|
+
return {
|
|
36
|
+
[utils_1.Selectors.INPUT_PROPERTY_OR_SETTER](node) {
|
|
37
|
+
const rawPropertyName = utils_1.ASTUtils.getRawText(node);
|
|
38
|
+
// The child that matched was just a literal initializer of a property definition
|
|
39
|
+
if (node.parent?.type === utils_2.TSESTree.AST_NODE_TYPES.PropertyDefinition) {
|
|
40
|
+
const initializingValue = node.parent.value;
|
|
41
|
+
if (initializingValue?.type === utils_2.TSESTree.AST_NODE_TYPES.Literal &&
|
|
42
|
+
rawPropertyName === utils_1.ASTUtils.getRawText(initializingValue) &&
|
|
43
|
+
node.range[0] === initializingValue.range[0] &&
|
|
44
|
+
node.range[1] === initializingValue.range[1]) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, rawPropertyName));
|
|
49
|
+
// Direct violation on the property name
|
|
50
|
+
if (hasDisallowedPrefix) {
|
|
51
|
+
context.report({
|
|
52
|
+
node,
|
|
53
|
+
messageId: 'noInputPrefix',
|
|
54
|
+
data: {
|
|
55
|
+
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Check if decorator alias has a violation
|
|
60
|
+
let aliasProperty;
|
|
61
|
+
if (!node.parent) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const inputDecorator = utils_1.ASTUtils.getDecorator(node.parent, 'Input');
|
|
65
|
+
if (inputDecorator &&
|
|
66
|
+
utils_1.ASTUtils.isCallExpression(inputDecorator.expression)) {
|
|
67
|
+
// Angular 16+ alias property syntax
|
|
68
|
+
aliasProperty = utils_1.ASTUtils.getDecoratorPropertyValue(inputDecorator, 'alias');
|
|
69
|
+
let aliasValue = '';
|
|
70
|
+
let aliasArg;
|
|
71
|
+
if (aliasProperty) {
|
|
72
|
+
aliasValue = utils_1.ASTUtils.getRawText(aliasProperty);
|
|
73
|
+
}
|
|
74
|
+
else if (inputDecorator.expression.arguments.length > 0 &&
|
|
75
|
+
(utils_1.ASTUtils.isLiteral(inputDecorator.expression.arguments[0]) ||
|
|
76
|
+
utils_1.ASTUtils.isTemplateLiteral(inputDecorator.expression.arguments[0]))) {
|
|
77
|
+
aliasArg = inputDecorator.expression.arguments[0];
|
|
78
|
+
aliasValue = utils_1.ASTUtils.getRawText(aliasArg);
|
|
79
|
+
}
|
|
80
|
+
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, aliasValue));
|
|
81
|
+
if (!hasDisallowedPrefix) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
return context.report({
|
|
85
|
+
node: aliasProperty || aliasArg || node,
|
|
86
|
+
messageId: 'noInputPrefix',
|
|
87
|
+
data: {
|
|
88
|
+
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
[utils_1.Selectors.INPUTS_METADATA_PROPERTY_LITERAL](node) {
|
|
94
|
+
const [propertyName, aliasName] = utils_1.ASTUtils.getRawText(node)
|
|
95
|
+
.replace(/\s/g, '')
|
|
96
|
+
.split(':');
|
|
97
|
+
const hasDisallowedPrefix = prefixes.some((prefix) => isDisallowedPrefix(prefix, propertyName, aliasName));
|
|
98
|
+
if (!hasDisallowedPrefix) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
context.report({
|
|
102
|
+
node,
|
|
103
|
+
messageId: 'noInputPrefix',
|
|
104
|
+
data: {
|
|
105
|
+
prefixes: (0, utils_1.toHumanReadableText)(prefixes),
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
function isDisallowedPrefix(prefix, propertyName, aliasName = '') {
|
|
113
|
+
const prefixPattern = new RegExp(`^${prefix}(([^a-z])|(?=$))`);
|
|
114
|
+
return prefixPattern.test(propertyName) || prefixPattern.test(aliasName);
|
|
115
|
+
}
|
|
116
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
117
|
+
rationale: "In HTML and Angular templates, attributes don't use prefixes like 'is' or 'has', so input properties shouldn't either. For example, prefer '@Input() disabled' over '@Input() isDisabled', so it's used in templates as '[disabled]=\"true\"' rather than '[isDisabled]=\"true\"'. This creates a more natural, HTML-like API for your components and follows Angular's style guide. The component class can still use prefixed names internally, but the input binding name (the public API) should follow HTML conventions.",
|
|
118
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Options = [{
|
|
2
|
+
readonly allowedNames?: readonly string[];
|
|
3
|
+
}];
|
|
4
|
+
export type MessageIds = 'noInputRename' | 'suggestRemoveAliasName' | 'suggestReplaceOriginalNameWithAliasName';
|
|
5
|
+
export declare const RULE_NAME = "no-input-rename";
|
|
6
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
10
|
+
export declare const RULE_DOCS_EXTENSION: {
|
|
11
|
+
rationale: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=no-input-rename.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-input-rename.d.ts","sourceRoot":"","sources":["../../src/rules/no-input-rename.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,OAAO,GAAG,CAAC;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AACtE,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,wBAAwB,GACxB,yCAAyC,CAAC;AAC9C,eAAO,MAAM,SAAS,oBAAoB,CAAC;;;;AAI3C,wBAgQG;AAqBH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|