@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.
Files changed (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/changes.json +10 -0
  4. package/dist/configs/README.md +44 -0
  5. package/dist/configs/all.json +54 -0
  6. package/dist/configs/recommended.json +18 -0
  7. package/dist/index.d.ts +233 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +145 -0
  10. package/dist/rules/component-class-suffix.d.ts +15 -0
  11. package/dist/rules/component-class-suffix.d.ts.map +1 -0
  12. package/dist/rules/component-class-suffix.js +56 -0
  13. package/dist/rules/component-max-inline-declarations.d.ts +17 -0
  14. package/dist/rules/component-max-inline-declarations.d.ts.map +1 -0
  15. package/dist/rules/component-max-inline-declarations.js +107 -0
  16. package/dist/rules/component-selector.d.ts +14 -0
  17. package/dist/rules/component-selector.d.ts.map +1 -0
  18. package/dist/rules/component-selector.js +218 -0
  19. package/dist/rules/computed-must-return.d.ts +11 -0
  20. package/dist/rules/computed-must-return.d.ts.map +1 -0
  21. package/dist/rules/computed-must-return.js +62 -0
  22. package/dist/rules/consistent-component-styles.d.ts +12 -0
  23. package/dist/rules/consistent-component-styles.d.ts.map +1 -0
  24. package/dist/rules/consistent-component-styles.js +97 -0
  25. package/dist/rules/contextual-decorator.d.ts +12 -0
  26. package/dist/rules/contextual-decorator.d.ts.map +1 -0
  27. package/dist/rules/contextual-decorator.js +61 -0
  28. package/dist/rules/contextual-lifecycle.d.ts +11 -0
  29. package/dist/rules/contextual-lifecycle.d.ts.map +1 -0
  30. package/dist/rules/contextual-lifecycle.js +61 -0
  31. package/dist/rules/directive-class-suffix.d.ts +13 -0
  32. package/dist/rules/directive-class-suffix.d.ts.map +1 -0
  33. package/dist/rules/directive-class-suffix.js +60 -0
  34. package/dist/rules/directive-selector.d.ts +14 -0
  35. package/dist/rules/directive-selector.d.ts.map +1 -0
  36. package/dist/rules/directive-selector.js +156 -0
  37. package/dist/rules/no-async-lifecycle-method.d.ts +11 -0
  38. package/dist/rules/no-async-lifecycle-method.d.ts.map +1 -0
  39. package/dist/rules/no-async-lifecycle-method.js +45 -0
  40. package/dist/rules/no-attribute-decorator.d.ts +11 -0
  41. package/dist/rules/no-attribute-decorator.d.ts.map +1 -0
  42. package/dist/rules/no-attribute-decorator.js +32 -0
  43. package/dist/rules/no-conflicting-lifecycle.d.ts +11 -0
  44. package/dist/rules/no-conflicting-lifecycle.d.ts.map +1 -0
  45. package/dist/rules/no-conflicting-lifecycle.js +74 -0
  46. package/dist/rules/no-developer-preview.d.ts +11 -0
  47. package/dist/rules/no-developer-preview.d.ts.map +1 -0
  48. package/dist/rules/no-developer-preview.js +45 -0
  49. package/dist/rules/no-duplicates-in-metadata-arrays.d.ts +11 -0
  50. package/dist/rules/no-duplicates-in-metadata-arrays.d.ts.map +1 -0
  51. package/dist/rules/no-duplicates-in-metadata-arrays.js +67 -0
  52. package/dist/rules/no-empty-lifecycle-method.d.ts +11 -0
  53. package/dist/rules/no-empty-lifecycle-method.d.ts.map +1 -0
  54. package/dist/rules/no-empty-lifecycle-method.js +75 -0
  55. package/dist/rules/no-experimental.d.ts +11 -0
  56. package/dist/rules/no-experimental.d.ts.map +1 -0
  57. package/dist/rules/no-experimental.js +45 -0
  58. package/dist/rules/no-forward-ref.d.ts +12 -0
  59. package/dist/rules/no-forward-ref.d.ts.map +1 -0
  60. package/dist/rules/no-forward-ref.js +33 -0
  61. package/dist/rules/no-implicit-take-until-destroyed.d.ts +11 -0
  62. package/dist/rules/no-implicit-take-until-destroyed.d.ts.map +1 -0
  63. package/dist/rules/no-implicit-take-until-destroyed.js +83 -0
  64. package/dist/rules/no-input-prefix.d.ts +13 -0
  65. package/dist/rules/no-input-prefix.d.ts.map +1 -0
  66. package/dist/rules/no-input-prefix.js +118 -0
  67. package/dist/rules/no-input-rename.d.ts +13 -0
  68. package/dist/rules/no-input-rename.d.ts.map +1 -0
  69. package/dist/rules/no-input-rename.js +213 -0
  70. package/dist/rules/no-inputs-metadata-property.d.ts +11 -0
  71. package/dist/rules/no-inputs-metadata-property.d.ts.map +1 -0
  72. package/dist/rules/no-inputs-metadata-property.js +53 -0
  73. package/dist/rules/no-lifecycle-call.d.ts +11 -0
  74. package/dist/rules/no-lifecycle-call.d.ts.map +1 -0
  75. package/dist/rules/no-lifecycle-call.js +49 -0
  76. package/dist/rules/no-output-native.d.ts +11 -0
  77. package/dist/rules/no-output-native.d.ts.map +1 -0
  78. package/dist/rules/no-output-native.js +47 -0
  79. package/dist/rules/no-output-on-prefix.d.ts +11 -0
  80. package/dist/rules/no-output-on-prefix.d.ts.map +1 -0
  81. package/dist/rules/no-output-on-prefix.js +48 -0
  82. package/dist/rules/no-output-rename.d.ts +11 -0
  83. package/dist/rules/no-output-rename.d.ts.map +1 -0
  84. package/dist/rules/no-output-rename.js +172 -0
  85. package/dist/rules/no-outputs-metadata-property.d.ts +11 -0
  86. package/dist/rules/no-outputs-metadata-property.d.ts.map +1 -0
  87. package/dist/rules/no-outputs-metadata-property.js +53 -0
  88. package/dist/rules/no-pipe-impure.d.ts +11 -0
  89. package/dist/rules/no-pipe-impure.d.ts.map +1 -0
  90. package/dist/rules/no-pipe-impure.js +42 -0
  91. package/dist/rules/no-queries-metadata-property.d.ts +11 -0
  92. package/dist/rules/no-queries-metadata-property.d.ts.map +1 -0
  93. package/dist/rules/no-queries-metadata-property.js +38 -0
  94. package/dist/rules/no-uncalled-signals.d.ts +12 -0
  95. package/dist/rules/no-uncalled-signals.d.ts.map +1 -0
  96. package/dist/rules/no-uncalled-signals.js +92 -0
  97. package/dist/rules/pipe-prefix.d.ts +15 -0
  98. package/dist/rules/pipe-prefix.d.ts.map +1 -0
  99. package/dist/rules/pipe-prefix.js +92 -0
  100. package/dist/rules/prefer-host-metadata-property.d.ts +10 -0
  101. package/dist/rules/prefer-host-metadata-property.d.ts.map +1 -0
  102. package/dist/rules/prefer-host-metadata-property.js +40 -0
  103. package/dist/rules/prefer-inject.d.ts +11 -0
  104. package/dist/rules/prefer-inject.d.ts.map +1 -0
  105. package/dist/rules/prefer-inject.js +86 -0
  106. package/dist/rules/prefer-on-push-component-change-detection.d.ts +11 -0
  107. package/dist/rules/prefer-on-push-component-change-detection.d.ts.map +1 -0
  108. package/dist/rules/prefer-on-push-component-change-detection.js +81 -0
  109. package/dist/rules/prefer-output-emitter-ref.d.ts +10 -0
  110. package/dist/rules/prefer-output-emitter-ref.d.ts.map +1 -0
  111. package/dist/rules/prefer-output-emitter-ref.js +30 -0
  112. package/dist/rules/prefer-output-readonly.d.ts +11 -0
  113. package/dist/rules/prefer-output-readonly.d.ts.map +1 -0
  114. package/dist/rules/prefer-output-readonly.js +51 -0
  115. package/dist/rules/prefer-signal-model.d.ts +10 -0
  116. package/dist/rules/prefer-signal-model.d.ts.map +1 -0
  117. package/dist/rules/prefer-signal-model.js +71 -0
  118. package/dist/rules/prefer-signals.d.ts +20 -0
  119. package/dist/rules/prefer-signals.d.ts.map +1 -0
  120. package/dist/rules/prefer-signals.js +174 -0
  121. package/dist/rules/prefer-standalone.d.ts +11 -0
  122. package/dist/rules/prefer-standalone.d.ts.map +1 -0
  123. package/dist/rules/prefer-standalone.js +66 -0
  124. package/dist/rules/relative-url-prefix.d.ts +11 -0
  125. package/dist/rules/relative-url-prefix.d.ts.map +1 -0
  126. package/dist/rules/relative-url-prefix.js +59 -0
  127. package/dist/rules/require-lifecycle-on-prototype.d.ts +11 -0
  128. package/dist/rules/require-lifecycle-on-prototype.d.ts.map +1 -0
  129. package/dist/rules/require-lifecycle-on-prototype.js +72 -0
  130. package/dist/rules/require-localize-metadata.d.ts +17 -0
  131. package/dist/rules/require-localize-metadata.d.ts.map +1 -0
  132. package/dist/rules/require-localize-metadata.js +123 -0
  133. package/dist/rules/runtime-localize.d.ts +11 -0
  134. package/dist/rules/runtime-localize.d.ts.map +1 -0
  135. package/dist/rules/runtime-localize.js +45 -0
  136. package/dist/rules/sort-keys-in-type-decorator.d.ts +16 -0
  137. package/dist/rules/sort-keys-in-type-decorator.d.ts.map +1 -0
  138. package/dist/rules/sort-keys-in-type-decorator.js +191 -0
  139. package/dist/rules/sort-lifecycle-methods.d.ts +11 -0
  140. package/dist/rules/sort-lifecycle-methods.d.ts.map +1 -0
  141. package/dist/rules/sort-lifecycle-methods.js +45 -0
  142. package/dist/rules/use-component-selector.d.ts +11 -0
  143. package/dist/rules/use-component-selector.d.ts.map +1 -0
  144. package/dist/rules/use-component-selector.js +41 -0
  145. package/dist/rules/use-component-view-encapsulation.d.ts +11 -0
  146. package/dist/rules/use-component-view-encapsulation.d.ts.map +1 -0
  147. package/dist/rules/use-component-view-encapsulation.js +49 -0
  148. package/dist/rules/use-injectable-provided-in.d.ts +13 -0
  149. package/dist/rules/use-injectable-provided-in.d.ts.map +1 -0
  150. package/dist/rules/use-injectable-provided-in.js +63 -0
  151. package/dist/rules/use-lifecycle-interface.d.ts +11 -0
  152. package/dist/rules/use-lifecycle-interface.d.ts.map +1 -0
  153. package/dist/rules/use-lifecycle-interface.js +65 -0
  154. package/dist/rules/use-pipe-transform-interface.d.ts +11 -0
  155. package/dist/rules/use-pipe-transform-interface.d.ts.map +1 -0
  156. package/dist/rules/use-pipe-transform-interface.js +49 -0
  157. package/dist/utils/create-eslint-rule.d.ts +8 -0
  158. package/dist/utils/create-eslint-rule.d.ts.map +1 -0
  159. package/dist/utils/create-eslint-rule.js +28 -0
  160. package/dist/utils/jsdoc.d.ts +11 -0
  161. package/dist/utils/jsdoc.d.ts.map +1 -0
  162. package/dist/utils/jsdoc.js +174 -0
  163. package/dist/utils/signals.d.ts +2 -0
  164. package/dist/utils/signals.d.ts.map +1 -0
  165. package/dist/utils/signals.js +10 -0
  166. package/package.json +56 -0
@@ -0,0 +1,61 @@
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 = 'contextual-decorator';
7
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
8
+ name: exports.RULE_NAME,
9
+ meta: {
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Ensures that classes use contextual decorators in their body',
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ contextualDecorator: 'Decorator out of context for "@{{classDecoratorName}}()"',
17
+ },
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ return {
22
+ 'MethodDefinition[kind=/^(get|set|method)$/], PropertyDefinition, TSParameterProperty'(node) {
23
+ validateNode(context, node);
24
+ },
25
+ };
26
+ },
27
+ });
28
+ function validateNode(context, node) {
29
+ if (!node.decorators?.length) {
30
+ return;
31
+ }
32
+ const classDeclaration = utils_1.ASTUtils.getNearestNodeFrom(node, utils_1.ASTUtils.isClassDeclaration);
33
+ if (!classDeclaration) {
34
+ return;
35
+ }
36
+ const classDecoratorName = utils_1.ASTUtils.getAngularClassDecorator(classDeclaration);
37
+ if (!classDecoratorName) {
38
+ return;
39
+ }
40
+ for (const decorator of node.decorators) {
41
+ validateDecorator(context, decorator, classDecoratorName);
42
+ }
43
+ }
44
+ function validateDecorator(context, decorator, classDecoratorName) {
45
+ const decoratorName = utils_1.ASTUtils.getDecoratorName(decorator);
46
+ if (!decoratorName || !utils_1.ASTUtils.isAngularInnerClassDecorator(decoratorName)) {
47
+ return;
48
+ }
49
+ const allowedDecorators = utils_1.ASTUtils.ANGULAR_CLASS_DECORATOR_MAPPER.get(classDecoratorName);
50
+ if (allowedDecorators?.has(decoratorName)) {
51
+ return;
52
+ }
53
+ context.report({
54
+ node: decorator,
55
+ messageId: 'contextualDecorator',
56
+ data: { classDecoratorName },
57
+ });
58
+ }
59
+ exports.RULE_DOCS_EXTENSION = {
60
+ rationale: `Angular decorators like @Input(), @Output(), @ViewChild(), and @HostBinding() are only meaningful in specific class types. For example, @Input() and @Output() only work in @Component or @Directive classes because they define the component/directive's API. Using these decorators in @Injectable() classes or @Pipe() classes will not work as expected, as Angular does not process these decorators in those contexts. This rule prevents bugs by ensuring decorators are only used where Angular will recognize and process them.`,
61
+ };
@@ -0,0 +1,11 @@
1
+ export type Options = [];
2
+ export type MessageIds = 'contextualLifecycle';
3
+ export declare const RULE_NAME = "contextual-lifecycle";
4
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"contextualLifecycle", [], 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=contextual-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextual-lifecycle.d.ts","sourceRoot":"","sources":["../../src/rules/contextual-lifecycle.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,qBAAqB,CAAC;AAC/C,eAAO,MAAM,SAAS,yBAAyB,CAAC;;;;AAEhD,wBA8DG;AAEH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
@@ -0,0 +1,61 @@
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 = 'contextual-lifecycle';
7
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
8
+ name: exports.RULE_NAME,
9
+ meta: {
10
+ type: 'problem',
11
+ docs: {
12
+ description: 'Ensures that lifecycle methods are used in a correct context',
13
+ recommended: 'recommended',
14
+ },
15
+ schema: [],
16
+ messages: {
17
+ contextualLifecycle: `Angular will not invoke the \`{{methodName}}\` lifecycle method within \`@{{classDecoratorName}}()\` classes`,
18
+ },
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ function checkContext({ parent }, decorator) {
23
+ const classDeclaration = parent;
24
+ const allowedMethods = utils_1.ASTUtils.ANGULAR_CLASS_DECORATOR_LIFECYCLE_METHOD_MAPPER.get(decorator);
25
+ const declaredMethods = utils_1.ASTUtils.getDeclaredMethods(classDeclaration);
26
+ for (const method of declaredMethods) {
27
+ const methodName = utils_1.ASTUtils.getMethodName(method);
28
+ if (!methodName ||
29
+ !utils_1.ASTUtils.isAngularLifecycleMethod(methodName) ||
30
+ allowedMethods?.has(methodName)) {
31
+ continue;
32
+ }
33
+ context.report({
34
+ node: method.key,
35
+ messageId: 'contextualLifecycle',
36
+ data: { classDecoratorName: decorator, methodName },
37
+ });
38
+ }
39
+ }
40
+ return {
41
+ [utils_1.Selectors.COMPONENT_CLASS_DECORATOR](node) {
42
+ checkContext(node, utils_1.ASTUtils.AngularClassDecorators.Component);
43
+ },
44
+ [utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR](node) {
45
+ checkContext(node, utils_1.ASTUtils.AngularClassDecorators.Directive);
46
+ },
47
+ [utils_1.Selectors.INJECTABLE_CLASS_DECORATOR](node) {
48
+ checkContext(node, utils_1.ASTUtils.AngularClassDecorators.Injectable);
49
+ },
50
+ [utils_1.Selectors.MODULE_CLASS_DECORATOR](node) {
51
+ checkContext(node, utils_1.ASTUtils.AngularClassDecorators.NgModule);
52
+ },
53
+ [utils_1.Selectors.PIPE_CLASS_DECORATOR](node) {
54
+ checkContext(node, utils_1.ASTUtils.AngularClassDecorators.Pipe);
55
+ },
56
+ };
57
+ },
58
+ });
59
+ exports.RULE_DOCS_EXTENSION = {
60
+ rationale: `Angular lifecycle hooks are only invoked for specific class types. For example, ngOnInit(), ngOnChanges(), and ngOnDestroy() are only called for components and directives, not for services (@Injectable), pipes (@Pipe), or modules (@NgModule). Defining these lifecycle methods in the wrong class type gives a false impression that they will be called, leading to bugs where initialization or cleanup logic never executes. This rule ensures lifecycle methods are only used where Angular will actually invoke them.`,
61
+ };
@@ -0,0 +1,13 @@
1
+ export type Options = [{
2
+ readonly suffixes: readonly string[];
3
+ }];
4
+ export type MessageIds = 'directiveClassSuffix';
5
+ export declare const RULE_NAME = "directive-class-suffix";
6
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"directiveClassSuffix", 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=directive-class-suffix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directive-class-suffix.d.ts","sourceRoot":"","sources":["../../src/rules/directive-class-suffix.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,sBAAsB,CAAC;AAChD,eAAO,MAAM,SAAS,2BAA2B,CAAC;;;;AAIlD,wBA4DG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -0,0 +1,60 @@
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 = 'directive-class-suffix';
7
+ const DEFAULT_SUFFIXES = ['Directive'];
8
+ const VALIDATOR_SUFFIX = 'Validator';
9
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
10
+ name: exports.RULE_NAME,
11
+ meta: {
12
+ type: 'suggestion',
13
+ docs: {
14
+ description: `Classes decorated with @Directive must have suffix "Directive" (or custom) in their name. Note: As of v20, this is no longer recommended by the Angular Team.`,
15
+ },
16
+ schema: [
17
+ {
18
+ type: 'object',
19
+ properties: {
20
+ suffixes: {
21
+ type: 'array',
22
+ items: {
23
+ type: 'string',
24
+ },
25
+ },
26
+ },
27
+ additionalProperties: false,
28
+ },
29
+ ],
30
+ messages: {
31
+ directiveClassSuffix: `Directive class names should end with one of these suffixes: {{suffixes}}`,
32
+ },
33
+ },
34
+ defaultOptions: [{ suffixes: DEFAULT_SUFFIXES }],
35
+ create(context, [{ suffixes }]) {
36
+ return {
37
+ [utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR](node) {
38
+ const selectorPropertyValue = utils_1.ASTUtils.getDecoratorPropertyValue(node, 'selector');
39
+ if (!selectorPropertyValue)
40
+ return;
41
+ const classParent = node.parent;
42
+ const className = utils_1.ASTUtils.getClassName(classParent);
43
+ const declaredInterfaceNames = utils_1.ASTUtils.getDeclaredInterfaceNames(classParent);
44
+ const hasValidatorInterface = declaredInterfaceNames.some((interfaceName) => interfaceName.endsWith(VALIDATOR_SUFFIX));
45
+ const allSuffixes = suffixes.concat(hasValidatorInterface ? VALIDATOR_SUFFIX : []);
46
+ if (!className ||
47
+ !allSuffixes.some((suffix) => className.endsWith(suffix))) {
48
+ context.report({
49
+ node: classParent.id ?? classParent,
50
+ messageId: 'directiveClassSuffix',
51
+ data: { suffixes: (0, utils_1.toHumanReadableText)(allSuffixes) },
52
+ });
53
+ }
54
+ },
55
+ };
56
+ },
57
+ });
58
+ exports.RULE_DOCS_EXTENSION = {
59
+ rationale: "Historically, appending 'Directive' to directive class names was recommended to distinguish directives from other classes. However, as of Angular v20, the Angular Team no longer recommends this convention, favoring simpler class names. This rule remains available for teams that have established this naming pattern and wish to maintain consistency in their existing codebase.",
60
+ };
@@ -0,0 +1,14 @@
1
+ import { SelectorUtils } from '@angular-eslint/utils';
2
+ export type Options = readonly [
3
+ SelectorUtils.SingleConfigOption | SelectorUtils.MultipleConfigOption
4
+ ];
5
+ export type MessageIds = 'prefixFailure' | 'styleFailure' | 'typeFailure' | 'selectorAfterPrefixFailure';
6
+ export declare const RULE_NAME = "directive-selector";
7
+ 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> & {
8
+ name: string;
9
+ };
10
+ export default _default;
11
+ export declare const RULE_DOCS_EXTENSION: {
12
+ rationale: string;
13
+ };
14
+ //# sourceMappingURL=directive-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directive-selector.d.ts","sourceRoot":"","sources":["../../src/rules/directive-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACd,MAAM,uBAAuB,CAAC;AAI/B,MAAM,MAAM,OAAO,GAAG,SAAS;IAC7B,aAAa,CAAC,kBAAkB,GAAG,aAAa,CAAC,oBAAoB;CACtE,CAAC;AACF,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,cAAc,GACd,aAAa,GACb,4BAA4B,CAAC;AACjC,eAAO,MAAM,SAAS,uBAAuB,CAAC;;;;AAE9C,wBA6KG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -0,0 +1,156 @@
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 = 'directive-selector';
7
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
8
+ name: exports.RULE_NAME,
9
+ meta: {
10
+ type: 'suggestion',
11
+ docs: {
12
+ description: 'Directive selectors should follow given naming rules. See more at https://angular.dev/style-guide#choosing-directive-selectors.',
13
+ },
14
+ schema: [
15
+ {
16
+ oneOf: [
17
+ // Single config object
18
+ {
19
+ type: 'object',
20
+ properties: {
21
+ type: {
22
+ oneOf: [
23
+ { type: 'string' },
24
+ {
25
+ type: 'array',
26
+ items: {
27
+ type: 'string',
28
+ enum: [
29
+ utils_1.SelectorUtils.OPTION_TYPE_ELEMENT,
30
+ utils_1.SelectorUtils.OPTION_TYPE_ATTRIBUTE,
31
+ ],
32
+ },
33
+ },
34
+ ],
35
+ },
36
+ prefix: {
37
+ oneOf: [{ type: 'string' }, { type: 'array' }],
38
+ },
39
+ style: {
40
+ type: 'string',
41
+ enum: [
42
+ utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
43
+ utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
44
+ ],
45
+ },
46
+ },
47
+ required: ['type', 'style'],
48
+ additionalProperties: false,
49
+ },
50
+ // Array of 1-2 config objects
51
+ {
52
+ type: 'array',
53
+ items: {
54
+ type: 'object',
55
+ properties: {
56
+ type: {
57
+ type: 'string',
58
+ enum: [
59
+ utils_1.SelectorUtils.OPTION_TYPE_ELEMENT,
60
+ utils_1.SelectorUtils.OPTION_TYPE_ATTRIBUTE,
61
+ ],
62
+ },
63
+ prefix: {
64
+ oneOf: [{ type: 'string' }, { type: 'array' }],
65
+ },
66
+ style: {
67
+ type: 'string',
68
+ enum: [
69
+ utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
70
+ utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
71
+ ],
72
+ },
73
+ },
74
+ additionalProperties: false,
75
+ required: ['type', 'style'],
76
+ },
77
+ minItems: 1,
78
+ maxItems: 2,
79
+ },
80
+ ],
81
+ },
82
+ ],
83
+ messages: {
84
+ prefixFailure: 'The selector should start with one of these prefixes: {{prefix}}',
85
+ styleFailure: 'The selector should be {{style}}',
86
+ typeFailure: 'The selector should be used as an {{type}}',
87
+ selectorAfterPrefixFailure: `There should be a selector after the {{prefix}} prefix`,
88
+ },
89
+ },
90
+ defaultOptions: [
91
+ {
92
+ type: undefined,
93
+ prefix: 'app', // Match default Angular CLI prefix
94
+ style: undefined,
95
+ },
96
+ ],
97
+ create(context, [options]) {
98
+ // Options are required by schema, so if undefined, ESLint will throw an error
99
+ if (!options) {
100
+ return {};
101
+ }
102
+ // Normalize options to a consistent format using shared utility
103
+ const configByType = utils_1.SelectorUtils.normalizeOptionsToConfigs(options);
104
+ return {
105
+ [utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR](node) {
106
+ const rawSelectors = utils_1.ASTUtils.getDecoratorPropertyValue(node, 'selector');
107
+ if (!rawSelectors) {
108
+ return;
109
+ }
110
+ // Parse selectors once for reuse
111
+ const parsedSelectors = utils_1.SelectorUtils.parseSelectorNode(rawSelectors);
112
+ if (!parsedSelectors || parsedSelectors.length === 0) {
113
+ return;
114
+ }
115
+ const applicableConfig = utils_1.SelectorUtils.getApplicableConfig(rawSelectors, configByType);
116
+ if (!applicableConfig) {
117
+ return;
118
+ }
119
+ const { type, prefix, style } = applicableConfig;
120
+ const isValidOptions = utils_1.SelectorUtils.checkValidOptions(type, prefix, style);
121
+ if (!isValidOptions) {
122
+ return;
123
+ }
124
+ const hasExpectedSelector = utils_1.SelectorUtils.checkSelector(rawSelectors, type, prefix, style, parsedSelectors);
125
+ if (hasExpectedSelector === null) {
126
+ return;
127
+ }
128
+ // Directive-specific validation logic (simpler than component)
129
+ if (!hasExpectedSelector.hasExpectedType) {
130
+ utils_1.SelectorUtils.reportTypeError(rawSelectors, type, context);
131
+ }
132
+ else if (!hasExpectedSelector.hasSelectorAfterPrefix) {
133
+ // Only report selector after prefix error if prefix is actually required
134
+ if (prefix !== undefined) {
135
+ utils_1.SelectorUtils.reportSelectorAfterPrefixError(rawSelectors, prefix, context);
136
+ }
137
+ }
138
+ else if (!hasExpectedSelector.hasExpectedStyle) {
139
+ utils_1.SelectorUtils.reportStyleError(rawSelectors, style, context);
140
+ }
141
+ else if (!hasExpectedSelector.hasExpectedPrefix) {
142
+ // Only report prefix error if prefix is actually required (not empty)
143
+ if (prefix !== undefined) {
144
+ const prefixArray = (0, utils_1.arrayify)(prefix);
145
+ if (prefixArray.length > 0) {
146
+ utils_1.SelectorUtils.reportPrefixError(rawSelectors, prefix, context);
147
+ }
148
+ }
149
+ }
150
+ },
151
+ };
152
+ },
153
+ });
154
+ exports.RULE_DOCS_EXTENSION = {
155
+ rationale: "Consistent directive selector naming conventions help identify which directives belong to your application versus third-party libraries, prevent naming collisions with native HTML attributes and other directives, and make code reviews and debugging easier. For example, using a camelCase attribute selector with a prefix like 'appHighlight' makes it immediately clear that this is a custom directive from your application.",
156
+ };
@@ -0,0 +1,11 @@
1
+ export type Options = [];
2
+ export type MessageIds = 'noAsyncLifecycleMethod';
3
+ export declare const RULE_NAME = "no-async-lifecycle-method";
4
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noAsyncLifecycleMethod", [], 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-async-lifecycle-method.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-async-lifecycle-method.d.ts","sourceRoot":"","sources":["../../src/rules/no-async-lifecycle-method.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAClD,eAAO,MAAM,SAAS,8BAA8B,CAAC;;;;AAErD,wBAyCG;AAEH,eAAO,MAAM,mBAAmB;;CAG/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 utils_1 = require("@angular-eslint/utils");
5
+ const create_eslint_rule_1 = require("../utils/create-eslint-rule");
6
+ exports.RULE_NAME = 'no-async-lifecycle-method';
7
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
8
+ name: exports.RULE_NAME,
9
+ meta: {
10
+ type: 'problem',
11
+ docs: {
12
+ description: `Angular Lifecycle methods should not be async. Angular does not wait for async lifecycle but the code incorrectly suggests it does.`,
13
+ },
14
+ schema: [],
15
+ messages: {
16
+ noAsyncLifecycleMethod: 'Angular Lifecycle method should not be async',
17
+ },
18
+ },
19
+ defaultOptions: [],
20
+ create(context) {
21
+ const angularDecoratorsPattern = (0, utils_1.toPattern)([
22
+ 'Component',
23
+ 'Directive',
24
+ 'Injectable',
25
+ 'NgModule',
26
+ 'Pipe',
27
+ ]);
28
+ const angularLifecycleMethodsPattern = (0, utils_1.toPattern)([
29
+ ...utils_1.ASTUtils.ANGULAR_LIFECYCLE_METHODS,
30
+ ]);
31
+ return {
32
+ [`${utils_1.Selectors.decoratorDefinition(angularDecoratorsPattern)} > ClassBody > MethodDefinition[key.name=${angularLifecycleMethodsPattern}]`](node) {
33
+ if (node.value.async === true) {
34
+ context.report({
35
+ node: node.key,
36
+ messageId: 'noAsyncLifecycleMethod',
37
+ });
38
+ }
39
+ },
40
+ };
41
+ },
42
+ });
43
+ exports.RULE_DOCS_EXTENSION = {
44
+ rationale: "Angular does not wait for async lifecycle methods to complete before continuing with the component lifecycle. If you make ngOnInit() async, Angular will call it and immediately move on without waiting for any await statements inside to resolve. This creates a misleading code pattern where it appears Angular will wait for asynchronous operations to complete, but it won't. For example, if ngOnInit() fetches data asynchronously, the component will continue rendering with potentially incomplete data. Instead of making lifecycle methods async, call async functions from within them and handle the promises appropriately, or use Angular patterns like resolvers, signals with async pipes, or reactive approaches with RxJS.",
45
+ };
@@ -0,0 +1,11 @@
1
+ export type Options = [];
2
+ export type MessageIds = 'noAttributeDecorator';
3
+ export declare const RULE_NAME = "no-attribute-decorator";
4
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noAttributeDecorator", [], 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-attribute-decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-attribute-decorator.d.ts","sourceRoot":"","sources":["../../src/rules/no-attribute-decorator.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,sBAAsB,CAAC;AAChD,eAAO,MAAM,SAAS,2BAA2B,CAAC;;;;AAElD,wBA0BG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -0,0 +1,32 @@
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
+ exports.RULE_NAME = 'no-attribute-decorator';
6
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
7
+ name: exports.RULE_NAME,
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: `The @Attribute decorator is used to obtain a single value for an attribute. This is a much less common use case than getting a stream of values (using @Input), so the @Attribute decorator is often mistakenly used when @Input is intended. This rule disallows the usage of @Attribute decorator entirely to prevent these mistakes.`,
12
+ },
13
+ schema: [],
14
+ messages: {
15
+ noAttributeDecorator: '@Attribute can only obtain a single value and is rarely what is required. Use @Input instead to retrieve a stream of values.',
16
+ },
17
+ },
18
+ defaultOptions: [],
19
+ create(context) {
20
+ return {
21
+ 'ClassDeclaration MethodDefinition[key.name="constructor"] Decorator[expression.callee.name="Attribute"]'(node) {
22
+ context.report({
23
+ node,
24
+ messageId: 'noAttributeDecorator',
25
+ });
26
+ },
27
+ };
28
+ },
29
+ });
30
+ exports.RULE_DOCS_EXTENSION = {
31
+ rationale: 'The @Attribute decorator is frequently misunderstood and misused. Unlike @Input(), which creates a binding that updates when the input value changes, @Attribute reads the attribute value only once during component construction and never updates. This single-read behavior is rarely what developers intend when they want to receive data from a parent component. In almost all cases, @Input() is the correct choice because it provides reactive updates. The @Attribute decorator is only appropriate for very specific optimization scenarios where you know the value will never change and want to avoid the overhead of change detection for that property. To prevent bugs from this common mistake, this rule disallows @Attribute entirely and encourages using @Input() instead, or modern signal-based inputs via input().',
32
+ };
@@ -0,0 +1,11 @@
1
+ export type Options = [];
2
+ export type MessageIds = 'noConflictingLifecycleInterface' | 'noConflictingLifecycleMethod';
3
+ export declare const RULE_NAME = "no-conflicting-lifecycle";
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-conflicting-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-conflicting-lifecycle.d.ts","sourceRoot":"","sources":["../../src/rules/no-conflicting-lifecycle.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAClB,iCAAiC,GACjC,8BAA8B,CAAC;AACnC,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAWpD,wBA8EG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -0,0 +1,74 @@
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-conflicting-lifecycle';
8
+ const LIFECYCLE_INTERFACES = [
9
+ utils_1.ASTUtils.AngularLifecycleInterfaces.DoCheck,
10
+ utils_1.ASTUtils.AngularLifecycleInterfaces.OnChanges,
11
+ ];
12
+ const LIFECYCLE_METHODS = [
13
+ utils_1.ASTUtils.AngularLifecycleMethods.ngDoCheck,
14
+ utils_1.ASTUtils.AngularLifecycleMethods.ngOnChanges,
15
+ ];
16
+ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
+ name: exports.RULE_NAME,
18
+ meta: {
19
+ type: 'suggestion',
20
+ deprecated: true,
21
+ docs: {
22
+ description: 'Ensures that directives do not implement conflicting lifecycle interfaces.',
23
+ },
24
+ schema: [],
25
+ messages: {
26
+ noConflictingLifecycleInterface: `Implementing ${utils_1.ASTUtils.AngularLifecycleInterfaces.DoCheck} and ${utils_1.ASTUtils.AngularLifecycleInterfaces.OnChanges} in a class is not recommended`,
27
+ noConflictingLifecycleMethod: `Declaring ${utils_1.ASTUtils.AngularLifecycleMethods.ngDoCheck} and ${utils_1.ASTUtils.AngularLifecycleMethods.ngOnChanges} method in a class is not recommended`,
28
+ },
29
+ },
30
+ defaultOptions: [],
31
+ create(context) {
32
+ const validateInterfaces = (node) => {
33
+ const declaredAngularLifecycleInterfaces = utils_1.ASTUtils.getDeclaredAngularLifecycleInterfaces(node);
34
+ const hasInterfaceConflictingLifecycle = LIFECYCLE_INTERFACES.every((lifecycleInterface) => declaredAngularLifecycleInterfaces.includes(lifecycleInterface));
35
+ if (!hasInterfaceConflictingLifecycle)
36
+ return;
37
+ const declaredInterfaces = utils_1.ASTUtils.getInterfaces(node);
38
+ const declaredAngularLifecycleInterfacesNodes = declaredInterfaces.filter((node) => {
39
+ const interfaceName = utils_1.ASTUtils.getInterfaceName(node);
40
+ return (interfaceName && utils_1.ASTUtils.isAngularLifecycleInterface(interfaceName));
41
+ });
42
+ for (const interFaceNode of declaredAngularLifecycleInterfacesNodes) {
43
+ context.report({
44
+ node: interFaceNode,
45
+ messageId: 'noConflictingLifecycleInterface',
46
+ });
47
+ }
48
+ };
49
+ const validateMethods = (node) => {
50
+ const declaredAngularLifecycleMethods = utils_1.ASTUtils.getDeclaredAngularLifecycleMethods(node);
51
+ const hasMethodConflictingLifecycle = LIFECYCLE_METHODS.every((lifecycleMethod) => declaredAngularLifecycleMethods.includes(lifecycleMethod));
52
+ if (!hasMethodConflictingLifecycle)
53
+ return;
54
+ const declaredMethods = utils_1.ASTUtils.getDeclaredMethods(node);
55
+ const declaredAngularLifecycleMethodNodes = declaredMethods.filter((node) => utils_2.ASTUtils.isIdentifier(node.key) &&
56
+ utils_1.ASTUtils.isAngularLifecycleMethod(node.key.name));
57
+ for (const method of declaredAngularLifecycleMethodNodes) {
58
+ context.report({
59
+ node: method,
60
+ messageId: 'noConflictingLifecycleMethod',
61
+ });
62
+ }
63
+ };
64
+ return {
65
+ ClassDeclaration(node) {
66
+ validateInterfaces(node);
67
+ validateMethods(node);
68
+ },
69
+ };
70
+ },
71
+ });
72
+ exports.RULE_DOCS_EXTENSION = {
73
+ rationale: 'This rule was created with the intent to prevent potential issues when both DoCheck and OnChanges lifecycle hooks are implemented together, as they both deal with change detection and could create confusing or duplicated logic. However, the rule has proven to be overly broad in practice. It triggers whenever a component or directive implements both hooks, regardless of whether they actually conflict or track the same data. In reality, there are legitimate use cases where both hooks can coexist without issues—for instance, using OnChanges to respond to specific input changes while using DoCheck for custom change detection logic on different data. Because the rule cannot accurately determine whether the hooks are actually conflicting (i.e., checking the same variables), it produces false positives and has been removed from the recommended configuration. While the rule was well-intentioned, it should not be relied upon in practice.',
74
+ };
@@ -0,0 +1,11 @@
1
+ export type Options = [];
2
+ export type MessageIds = 'noDeveloperPreview';
3
+ export declare const RULE_NAME = "no-developer-preview";
4
+ declare const _default: import("@typescript-eslint/utils/eslint-utils").RuleModule<"noDeveloperPreview", [], 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-developer-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-developer-preview.d.ts","sourceRoot":"","sources":["../../src/rules/no-developer-preview.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AACzB,MAAM,MAAM,UAAU,GAAG,oBAAoB,CAAC;AAC9C,eAAO,MAAM,SAAS,yBAAyB,CAAC;;;;AAEhD,wBAsCG;AAEH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}