@angular-eslint/eslint-plugin 22.2.1-alpha.1 → 22.2.1-alpha.11

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 (56) hide show
  1. package/dist/index.d.ts +3 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/rules/component-class-suffix.js +5 -5
  4. package/dist/rules/component-max-inline-declarations.js +7 -7
  5. package/dist/rules/computed-must-return.js +1 -1
  6. package/dist/rules/consistent-component-styles.js +1 -1
  7. package/dist/rules/contextual-decorator.js +1 -1
  8. package/dist/rules/contextual-lifecycle.js +1 -1
  9. package/dist/rules/directive-class-suffix.js +1 -1
  10. package/dist/rules/inject-at-top.js +1 -1
  11. package/dist/rules/no-async-lifecycle-method.js +1 -1
  12. package/dist/rules/no-attribute-decorator.js +1 -1
  13. package/dist/rules/no-developer-preview.js +1 -1
  14. package/dist/rules/no-duplicates-in-metadata-arrays.js +1 -1
  15. package/dist/rules/no-empty-lifecycle-method.js +1 -1
  16. package/dist/rules/no-experimental.js +1 -1
  17. package/dist/rules/no-forward-ref.js +1 -1
  18. package/dist/rules/no-implicit-take-until-destroyed.d.ts.map +1 -1
  19. package/dist/rules/no-implicit-take-until-destroyed.js +16 -6
  20. package/dist/rules/no-input-prefix.js +1 -1
  21. package/dist/rules/no-input-rename.js +1 -1
  22. package/dist/rules/no-inputs-metadata-property.js +1 -1
  23. package/dist/rules/no-lifecycle-call.js +1 -1
  24. package/dist/rules/no-output-native.js +1 -1
  25. package/dist/rules/no-output-on-prefix.js +1 -1
  26. package/dist/rules/no-output-rename.js +1 -1
  27. package/dist/rules/no-outputs-metadata-property.js +1 -1
  28. package/dist/rules/no-pipe-impure.js +1 -1
  29. package/dist/rules/no-queries-metadata-property.js +1 -1
  30. package/dist/rules/no-uncalled-signals.js +1 -1
  31. package/dist/rules/pipe-prefix.js +5 -5
  32. package/dist/rules/prefer-host-metadata-property.js +1 -1
  33. package/dist/rules/prefer-inject.js +1 -1
  34. package/dist/rules/prefer-on-push-component-change-detection.js +1 -1
  35. package/dist/rules/prefer-output-emitter-ref.js +1 -1
  36. package/dist/rules/prefer-output-readonly.js +1 -1
  37. package/dist/rules/prefer-service-decorator.js +1 -1
  38. package/dist/rules/prefer-signal-model.d.ts +7 -1
  39. package/dist/rules/prefer-signal-model.d.ts.map +1 -1
  40. package/dist/rules/prefer-signal-model.js +118 -40
  41. package/dist/rules/prefer-signals.js +1 -1
  42. package/dist/rules/prefer-standalone.js +1 -1
  43. package/dist/rules/relative-url-prefix.js +1 -1
  44. package/dist/rules/require-lifecycle-on-prototype.js +1 -1
  45. package/dist/rules/require-localize-metadata.js +1 -1
  46. package/dist/rules/runtime-localize.js +1 -1
  47. package/dist/rules/sort-keys-in-type-decorator.js +1 -1
  48. package/dist/rules/sort-lifecycle-methods.js +1 -1
  49. package/dist/rules/use-component-selector.js +1 -1
  50. package/dist/rules/use-component-view-encapsulation.js +1 -1
  51. package/dist/rules/use-injectable-provided-in.js +1 -1
  52. package/dist/rules/use-lifecycle-interface.js +1 -1
  53. package/dist/rules/use-pipe-transform-interface.js +1 -1
  54. package/dist/utils/create-eslint-rule.d.ts.map +1 -1
  55. package/dist/utils/create-eslint-rule.js +1 -24
  56. package/package.json +4 -4
package/dist/index.d.ts CHANGED
@@ -108,7 +108,9 @@ declare const _default: {
108
108
  "prefer-service-decorator": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferServiceDecorator", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
109
109
  name: string;
110
110
  };
111
- "prefer-signal-model": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferSignalModel", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
111
+ "prefer-signal-model": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferSignalModel", [{
112
+ useTypeChecking: boolean;
113
+ }], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
112
114
  name: string;
113
115
  };
114
116
  "prefer-signals": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/prefer-signals").MessageIds, [{
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuJA,kBAsDE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuJA,kBAsDE"}
@@ -28,12 +28,12 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
28
28
  messages: {
29
29
  componentClassSuffix: `Component class names should end with one of these suffixes: {{suffixes}}`,
30
30
  },
31
+ defaultOptions: [
32
+ {
33
+ suffixes: ['Component'],
34
+ },
35
+ ],
31
36
  },
32
- defaultOptions: [
33
- {
34
- suffixes: ['Component'],
35
- },
36
- ],
37
37
  create(context, [{ suffixes }]) {
38
38
  return {
39
39
  [utils_1.Selectors.COMPONENT_CLASS_DECORATOR](node) {
@@ -38,14 +38,14 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
38
38
  messages: {
39
39
  componentMaxInlineDeclarations: `\`{{propertyType}}\` has too many lines ({{lineCount}}). Maximum allowed is {{max}}`,
40
40
  },
41
+ defaultOptions: [
42
+ {
43
+ template: DEFAULT_TEMPLATE_LIMIT,
44
+ styles: DEFAULT_STYLES_LIMIT,
45
+ animations: DEFAULT_ANIMATIONS_LIMIT,
46
+ },
47
+ ],
41
48
  },
42
- defaultOptions: [
43
- {
44
- template: DEFAULT_TEMPLATE_LIMIT,
45
- styles: DEFAULT_STYLES_LIMIT,
46
- animations: DEFAULT_ANIMATIONS_LIMIT,
47
- },
48
- ],
49
49
  create(context, [{ template = DEFAULT_TEMPLATE_LIMIT, styles = DEFAULT_STYLES_LIMIT, animations = DEFAULT_ANIMATIONS_LIMIT, },]) {
50
50
  return {
51
51
  [`${utils_1.Selectors.COMPONENT_CLASS_DECORATOR} Property[key.name='template']`]({ value, }) {
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  computedMissingReturn: 'computed() is missing a return value',
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  const functionStack = [];
22
22
  function enterFunction(node) {
@@ -24,8 +24,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
24
24
  useStylesArray: 'Use a `string[]` instead of a `string` for the `styles` property',
25
25
  useStylesString: 'Use a `string` instead of a `string[]` for the `styles` property',
26
26
  },
27
+ defaultOptions: ['string'],
27
28
  },
28
- defaultOptions: ['string'],
29
29
  create(context, [mode]) {
30
30
  const { COMPONENT_CLASS_DECORATOR, metadataProperty } = utils_1.Selectors;
31
31
  const LITERAL_OR_TEMPLATE_LITERAL = ':matches(Literal, TemplateLiteral)';
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  contextualDecorator: 'Decorator out of context for "@{{classDecoratorName}}()"',
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  return {
22
22
  'MethodDefinition[kind=/^(get|set|method)$/], PropertyDefinition, TSParameterProperty'(node) {
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  contextualLifecycle: `Angular will not invoke the \`{{methodName}}\` lifecycle method within \`@{{classDecoratorName}}()\` classes`,
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  function checkContext({ parent }, decorator) {
23
23
  const classDeclaration = parent;
@@ -30,8 +30,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
30
30
  messages: {
31
31
  directiveClassSuffix: `Directive class names should end with one of these suffixes: {{suffixes}}`,
32
32
  },
33
+ defaultOptions: [{ suffixes: DEFAULT_SUFFIXES }],
33
34
  },
34
- defaultOptions: [{ suffixes: DEFAULT_SUFFIXES }],
35
35
  create(context, [{ suffixes }]) {
36
36
  return {
37
37
  [utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR](node) {
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  injectAtTop: 'Move this inject() to the top of the class. Class fields are initialized in the order they are written, so anything declared above this line cannot safely use the service yet.',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const angularDecoratorsPattern = (0, utils_1.toPattern)([
23
23
  'Component',
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  noAsyncLifecycleMethod: 'Angular Lifecycle method should not be async',
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  const angularDecoratorsPattern = (0, utils_1.toPattern)([
22
22
  'Component',
@@ -14,8 +14,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
14
14
  messages: {
15
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
16
  },
17
+ defaultOptions: [],
17
18
  },
18
- defaultOptions: [],
19
19
  create(context) {
20
20
  return {
21
21
  'ClassDeclaration MethodDefinition[key.name="constructor"] Decorator[expression.callee.name="Attribute"]'(node) {
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noDeveloperPreview: '`{{name}}` is in developer preview',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const services = (0, eslint_utils_1.getParserServices)(context);
23
23
  const checker = services.program.getTypeChecker();
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noDuplicatesInMetadataArrays: 'Entry is duplicated in metadata array',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const selectors = [
23
23
  // https://angular.dev/api/core/NgModule
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  noEmptyLifecycleMethod: 'Lifecycle methods should not be empty',
19
19
  suggestRemoveLifecycleMethod: 'Remove lifecycle method',
20
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  const sourceCode = context.sourceCode;
25
25
  const angularDecoratorsPattern = (0, utils_1.toPattern)([
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noExperimental: '`{{name}}` is experimental',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const services = (0, eslint_utils_1.getParserServices)(context);
23
23
  const checker = services.program.getTypeChecker();
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  noForwardRef: `Avoid using \`${exports.FORWARD_REF}\``,
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  return {
22
22
  [`CallExpression[callee.type="Identifier"][callee.name="${exports.FORWARD_REF}"]`](node) {
@@ -1 +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;AAwMH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
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;AAiNH,eAAO,MAAM,mBAAmB;;CAE/B,CAAC"}
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  messages: {
19
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
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  return {
25
25
  CallExpression(node) {
@@ -89,16 +89,26 @@ function isMethodCalledFromInjectionContext(method, classDeclaration) {
89
89
  return false;
90
90
  }
91
91
  const isPrivateField = method.key.type === utils_2.AST_NODE_TYPES.PrivateIdentifier;
92
+ let isCalledFromInjectionContext = false;
92
93
  for (const member of classDeclaration.body.body) {
93
- if (!isConstructorMethod(member) &&
94
- !utils_1.ASTUtils.isPropertyDefinition(member)) {
94
+ // Ignore recursive calls from the method to itself
95
+ if (member === method) {
95
96
  continue;
96
97
  }
97
- if (containsCallToMethod(member, methodName, isPrivateField)) {
98
- return true;
98
+ if (!containsCallToMethod(member, methodName, isPrivateField)) {
99
+ continue;
100
+ }
101
+ if (isConstructorMethod(member) || utils_1.ASTUtils.isPropertyDefinition(member)) {
102
+ isCalledFromInjectionContext = true;
103
+ }
104
+ else {
105
+ // The method is also called from somewhere that is not an injection
106
+ // context (e.g. a lifecycle hook or a regular method), so we cannot
107
+ // assume that `takeUntilDestroyed()` will always run within one.
108
+ return false;
99
109
  }
100
110
  }
101
- return false;
111
+ return isCalledFromInjectionContext;
102
112
  }
103
113
  function isASTNode(value) {
104
114
  return (value !== null &&
@@ -29,8 +29,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
29
29
  messages: {
30
30
  noInputPrefix: 'Input bindings, including aliases, should not be named, nor prefixed by {{prefixes}}',
31
31
  },
32
+ defaultOptions: [{ prefixes: [] }],
32
33
  },
33
- defaultOptions: [{ prefixes: [] }],
34
34
  create(context, [{ prefixes }]) {
35
35
  return {
36
36
  [utils_1.Selectors.INPUT_PROPERTY_OR_SETTER](node) {
@@ -37,8 +37,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
37
37
  suggestRemoveAliasName: 'Remove alias name',
38
38
  suggestReplaceOriginalNameWithAliasName: 'Remove alias name and use it as the original name',
39
39
  },
40
+ defaultOptions: [{ allowedNames: [] }],
40
41
  },
41
- defaultOptions: [{ allowedNames: [] }],
42
42
  create(context, [{ allowedNames = [] }]) {
43
43
  let selectors = new Set();
44
44
  const ariaAttributeKeys = (0, utils_1.getAriaAttributeKeys)();
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  messages: {
19
19
  noInputsMetadataProperty: `Use \`@Input\` rather than the \`${METADATA_PROPERTY_NAME}\` metadata property`,
20
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  return {
25
25
  [`${utils_1.Selectors.COMPONENT_OR_DIRECTIVE_CLASS_DECORATOR} ${utils_1.Selectors.metadataProperty(METADATA_PROPERTY_NAME)}`](node) {
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noLifecycleCall: 'Avoid explicit calls to lifecycle methods',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const angularLifeCycleMethodsPattern = (0, utils_1.toPattern)([
23
23
  ...utils_1.ASTUtils.ANGULAR_LIFECYCLE_METHODS,
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noOutputNative: 'Output bindings, including aliases, should not be named as standard DOM events',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  const nativeEventNames = (0, utils_1.getNativeEventNames)();
23
23
  const selectors = [
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  messages: {
18
18
  noOutputOnPrefix: `Output bindings, including aliases, should not be named "on", nor prefixed with it (${STYLE_GUIDE_LINK})`,
19
19
  },
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  const outputOnPattern = /^on(([^a-z])|(?=$))/;
24
24
  const selectors = [
@@ -22,8 +22,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
22
22
  suggestRemoveAliasName: 'Remove alias name',
23
23
  suggestReplaceOriginalNameWithAliasName: 'Remove alias name and use it as the original name',
24
24
  },
25
+ defaultOptions: [],
25
26
  },
26
- defaultOptions: [],
27
27
  create(context) {
28
28
  let selectors = new Set();
29
29
  return {
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  messages: {
19
19
  noOutputsMetadataProperty: `Use \`@Output\` rather than the \`${METADATA_PROPERTY_NAME}\` metadata property`,
20
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  return {
25
25
  [`${utils_1.Selectors.COMPONENT_OR_DIRECTIVE_CLASS_DECORATOR} ${utils_1.Selectors.metadataProperty(METADATA_PROPERTY_NAME)}`](node) {
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  noPipeImpure: 'Impure pipes should be avoided because they are invoked on each change-detection cycle',
18
18
  suggestRemovePipeImpure: 'Remove `pure` property',
19
19
  },
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  const sourceCode = context.sourceCode;
24
24
  return {
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  noQueriesMetadataProperty: `Use @${utils_1.ASTUtils.AngularInnerClassDecorators.Output} rather than the \`${METADATA_PROPERTY_NAME}\` metadata property`,
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  return {
23
23
  [utils_1.Selectors.COMPONENT_OR_DIRECTIVE_CLASS_DECORATOR](node) {
@@ -33,8 +33,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
33
33
  noUncalledSignals: 'Doing logic operations on signals will give unexpected results, you probably want to invoke the signal to get its value',
34
34
  suggestCallSignal: 'Call this signal to get its value.',
35
35
  },
36
+ defaultOptions: [],
36
37
  },
37
- defaultOptions: [],
38
38
  create(context) {
39
39
  const services = utils_1.ESLintUtils.getParserServices(context);
40
40
  function checkForUncalledSignal(node) {
@@ -30,12 +30,12 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
30
30
  pipePrefix: '@Pipes should be prefixed with {{prefixes}}',
31
31
  selectorAfterPrefixFailure: '@Pipes should have a selector after the {{prefixes}} prefix',
32
32
  },
33
+ defaultOptions: [
34
+ {
35
+ prefixes: [],
36
+ },
37
+ ],
33
38
  },
34
- defaultOptions: [
35
- {
36
- prefixes: [],
37
- },
38
- ],
39
39
  create(context, [{ prefixes }]) {
40
40
  function checkValidOption(prefixes) {
41
41
  return Array.isArray(prefixes) && prefixes.length > 0;
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  preferHostMetadataPropertyForBinding: 'Prefer using the `host` metadata property in the `@Component` decorator for host bindings instead of the `@HostBinding` decorator.',
17
17
  preferHostMetadataPropertyForListener: 'Prefer using the `host` metadata property in the `@Component` decorator for host listeners instead of the `@HostListener` decorator.',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  return {
23
23
  [utils_1.Selectors.HOST_BINDING_DECORATOR]: (node) => {
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  messages: {
18
18
  preferInject: "Prefer using the inject() function over constructor parameter injection. Use Angular's migration schematic to automatically refactor: ng generate @angular/core:inject",
19
19
  },
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  const angularDecoratorsPattern = (0, utils_1.toPattern)([
24
24
  'Component',
@@ -35,8 +35,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
35
35
  suggestRemoveChangeDetection: `Remove \`${METADATA_PROPERTY_NAME}\` to use the default (\`${STRATEGY_ON_PUSH}\`)`,
36
36
  redundantOnPushComponentChangeDetection: `\`${METADATA_PROPERTY_NAME}: ${STRATEGY_ON_PUSH}\` is redundant because \`${STRATEGY_ON_PUSH}\` is the default change detection strategy`,
37
37
  },
38
+ defaultOptions: [DEFAULT_OPTIONS],
38
39
  },
39
- defaultOptions: [DEFAULT_OPTIONS],
40
40
  create(context, [{ allowExplicitOnPush }]) {
41
41
  const sourceCode = context.sourceCode;
42
42
  const changeDetectionMetadataProperty = utils_1.Selectors.metadataProperty(METADATA_PROPERTY_NAME);
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  preferOutputEmitterRef: 'Use `OutputEmitterRef` via `output()` for Component and Directive outputs rather than the legacy `@Output()` decorator',
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  return {
22
22
  [utils_1.Selectors.OUTPUT_DECORATOR]: (node) => {
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  preferOutputReadonly: 'Prefer to declare `{{type}}` as `readonly` since they are not supposed to be reassigned',
18
18
  suggestAddReadonlyModifier: 'Add `readonly` modifier',
19
19
  },
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  return {
24
24
  [`PropertyDefinition:not([readonly=true]) > ${utils_1.Selectors.OUTPUT_DECORATOR}`]({ parent: { key }, }) {
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  messages: {
18
18
  preferServiceDecorator: "Use the `@Service()` decorator instead of `@Injectable({ providedIn: 'root' })`",
19
19
  },
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  return {
24
24
  [utils_1.Selectors.INJECTABLE_CLASS_DECORATOR](node) {
@@ -1,6 +1,12 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ type Options = [
3
+ {
4
+ useTypeChecking: boolean;
5
+ }
6
+ ];
1
7
  export type MessageIds = 'preferSignalModel';
2
8
  export declare const RULE_NAME = "prefer-signal-model";
3
- declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferSignalModel", [], import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
9
+ declare const _default: ESLintUtils.RuleModule<"preferSignalModel", Options, import("../utils/create-eslint-rule").RuleDocs, ESLintUtils.RuleListener> & {
4
10
  name: string;
5
11
  };
6
12
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-signal-model.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-signal-model.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAC7C,eAAO,MAAM,SAAS,wBAAwB,CAAC;;;;AAE/C,wBA0EG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
1
+ {"version":3,"file":"prefer-signal-model.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-signal-model.ts"],"names":[],"mappings":"AASA,OAAO,EAAkB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAIvE,KAAK,OAAO,GAAG;IACb;QACE,eAAe,EAAE,OAAO,CAAC;KAC1B;CACF,CAAC;AAMF,MAAM,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAC7C,eAAO,MAAM,SAAS,wBAAwB,CAAC;;;;AA8B/C,wBAuKG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -1,9 +1,25 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
4
7
  const utils_1 = require("@angular-eslint/utils");
8
+ const utils_2 = require("@typescript-eslint/utils");
9
+ const typescript_1 = __importDefault(require("typescript"));
5
10
  const create_eslint_rule_1 = require("../utils/create-eslint-rule");
11
+ const DEFAULT_OPTIONS = {
12
+ useTypeChecking: false,
13
+ };
6
14
  exports.RULE_NAME = 'prefer-signal-model';
15
+ function hasTransformOption(options) {
16
+ return (options?.type === utils_2.AST_NODE_TYPES.ObjectExpression &&
17
+ options.properties.some((property) => property.type === utils_2.AST_NODE_TYPES.Property &&
18
+ ((property.key.type === utils_2.AST_NODE_TYPES.Identifier &&
19
+ property.key.name === 'transform') ||
20
+ (property.key.type === utils_2.AST_NODE_TYPES.Literal &&
21
+ property.key.value === 'transform'))));
22
+ }
7
23
  exports.default = (0, create_eslint_rule_1.createESLintRule)({
8
24
  name: exports.RULE_NAME,
9
25
  meta: {
@@ -12,54 +28,116 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
12
28
  description: 'Use `model` instead of `input` and `output` for two-way bindings',
13
29
  },
14
30
  fixable: 'code',
15
- schema: [],
31
+ schema: [
32
+ {
33
+ type: 'object',
34
+ properties: {
35
+ useTypeChecking: {
36
+ type: 'boolean',
37
+ default: DEFAULT_OPTIONS.useTypeChecking,
38
+ },
39
+ },
40
+ additionalProperties: false,
41
+ },
42
+ ],
16
43
  messages: {
17
44
  preferSignalModel: 'Use `model` for two-way bindings instead of `input()` and `output()`',
18
45
  },
46
+ defaultOptions: [{ ...DEFAULT_OPTIONS }],
19
47
  },
20
- defaultOptions: [],
21
- create(context) {
48
+ create(context, [{ useTypeChecking = DEFAULT_OPTIONS.useTypeChecking }]) {
49
+ const { sourceCode } = context;
22
50
  const inputs = new Map();
23
51
  const outputs = new Map();
52
+ let services;
53
+ function getTypeServices() {
54
+ return (services ??= utils_2.ESLintUtils.getParserServices(context));
55
+ }
56
+ function createSignalCollector(signals, { hasInitialValueArgument }) {
57
+ return (node) => {
58
+ const options = node.arguments[hasInitialValueArgument ? 1 : 0];
59
+ // `model()` has no transform support.
60
+ // https://github.com/angular/angular/issues/55166#issuecomment-2032150999
61
+ if (hasTransformOption(options)) {
62
+ return;
63
+ }
64
+ const property = node.parent;
65
+ signals.set(utils_1.ASTUtils.getPropertyDefinitionName(property), {
66
+ property,
67
+ callee: (node.callee.type === utils_2.AST_NODE_TYPES.MemberExpression
68
+ ? node.callee.object
69
+ : node.callee),
70
+ typeArgument: node.typeArguments?.params[0],
71
+ initialValue: hasInitialValueArgument ? node.arguments[0] : undefined,
72
+ });
73
+ };
74
+ }
75
+ function getValueType({ typeArgument, initialValue }) {
76
+ const typeServices = getTypeServices();
77
+ if (typeArgument) {
78
+ return typeServices.getTypeAtLocation(typeArgument);
79
+ }
80
+ if (initialValue) {
81
+ return typeServices.program
82
+ .getTypeChecker()
83
+ .getBaseTypeOfLiteralType(typeServices.getTypeAtLocation(initialValue));
84
+ }
85
+ return undefined;
86
+ }
87
+ function haveEquallyWrittenTypes(input, output) {
88
+ return (!input.typeArgument ||
89
+ !output.typeArgument ||
90
+ sourceCode.getText(input.typeArgument) ===
91
+ sourceCode.getText(output.typeArgument));
92
+ }
93
+ function haveMergeableTypes(input, output) {
94
+ if (!useTypeChecking) {
95
+ return haveEquallyWrittenTypes(input, output);
96
+ }
97
+ const inputType = getValueType(input);
98
+ const outputType = getValueType(output);
99
+ if (!inputType || !outputType) {
100
+ return true;
101
+ }
102
+ // A type argument that does not resolve becomes the error type, which is
103
+ // assignable in both directions, so only the written text is trustworthy.
104
+ if ((inputType.flags | outputType.flags) & typescript_1.default.TypeFlags.Any) {
105
+ return haveEquallyWrittenTypes(input, output);
106
+ }
107
+ // Mutual assignability stands in for the internal `isTypeIdenticalTo`;
108
+ // the same type written twice yields two distinct `ts.Type` objects.
109
+ const checker = getTypeServices().program.getTypeChecker();
110
+ return (checker.isTypeAssignableTo(inputType, outputType) &&
111
+ checker.isTypeAssignableTo(outputType, inputType));
112
+ }
24
113
  return {
25
- "PropertyDefinition > CallExpression[callee.name='input']"(node) {
26
- const propertyDef = node.parent;
27
- const propertyName = utils_1.ASTUtils.getPropertyDefinitionName(propertyDef);
28
- inputs.set(propertyName, propertyDef);
29
- },
30
- "PropertyDefinition > CallExpression[callee.name='output']"(node) {
31
- const propertyDef = node.parent;
32
- const propertyName = utils_1.ASTUtils.getPropertyDefinitionName(propertyDef);
33
- outputs.set(propertyName, propertyDef);
34
- },
114
+ "PropertyDefinition > CallExpression[callee.name='input']": createSignalCollector(inputs, { hasInitialValueArgument: true }),
115
+ "PropertyDefinition > CallExpression[callee.object.name='input'][callee.property.name='required']": createSignalCollector(inputs, { hasInitialValueArgument: false }),
116
+ "PropertyDefinition > CallExpression[callee.name='output']": createSignalCollector(outputs, { hasInitialValueArgument: false }),
35
117
  'ClassDeclaration:exit'() {
36
- for (const [inputName, inputProperty] of inputs) {
37
- const outputName = `${inputName}Change`;
38
- const outputProperty = outputs.get(outputName);
39
- if (outputProperty) {
40
- // Report on the input property
41
- context.report({
42
- node: inputProperty,
43
- messageId: 'preferSignalModel',
44
- fix: (fixer) => {
45
- const sourceCode = context.sourceCode;
46
- const inputText = sourceCode.getText(inputProperty);
47
- const fixedInputText = inputText.replace(/\binput\b/, 'model');
48
- return [
49
- utils_1.RuleFixes.getImportAddFix({
50
- fixer,
51
- importName: 'model',
52
- moduleName: '@angular/core',
53
- node: inputProperty,
54
- }),
55
- fixer.replaceText(inputProperty, fixedInputText),
56
- fixer.remove(outputProperty),
57
- ].filter(utils_1.isNotNullOrUndefined);
58
- },
59
- });
60
- }
118
+ const twoWayBindings = [...inputs]
119
+ .map(([name, input]) => ({
120
+ input,
121
+ output: outputs.get(`${name}Change`),
122
+ }))
123
+ .filter((binding) => binding.output !== undefined &&
124
+ haveMergeableTypes(binding.input, binding.output));
125
+ for (const { input, output } of twoWayBindings) {
126
+ context.report({
127
+ node: input.property,
128
+ messageId: 'preferSignalModel',
129
+ fix: (fixer) => [
130
+ utils_1.RuleFixes.getImportAddFix({
131
+ fixer,
132
+ importName: 'model',
133
+ moduleName: '@angular/core',
134
+ node: input.property,
135
+ }),
136
+ fixer.replaceText(input.callee, 'model'),
137
+ fixer.remove(output.property),
138
+ ].filter(utils_1.isNotNullOrUndefined),
139
+ });
61
140
  }
62
- // Clear the maps for the next class
63
141
  inputs.clear();
64
142
  outputs.clear();
65
143
  },
@@ -67,5 +145,5 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
67
145
  },
68
146
  });
69
147
  exports.RULE_DOCS_EXTENSION = {
70
- rationale: "The model() function is Angular's modern API for two-way bindings, combining both input and output into a single signal. When you have an input property paired with an output property that follows the naming pattern of `propertyChange` (e.g., `enabled` input with `enabledChange` output), this is the traditional pattern for two-way binding. The model() function provides a cleaner, more concise way to express this pattern with better type safety and integration with Angular's signal ecosystem. It eliminates the boilerplate of managing separate input and output properties while maintaining the same two-way binding functionality.",
148
+ rationale: "The model() function is Angular's modern API for two-way bindings, combining both input and output into a single signal. When you have an input property paired with an output property that follows the naming pattern of `propertyChange` (e.g., `enabled` input with `enabledChange` output), this is the traditional pattern for two-way binding. The model() function provides a cleaner, more concise way to express this pattern with better type safety and integration with Angular's signal ecosystem. It eliminates the boilerplate of managing separate input and output properties while maintaining the same two-way binding functionality.\n\nBecause `model()` exposes a single type for both directions, only pairs whose `input` and `output` types match are reported. By default the written type arguments are compared as text, and a pair is assumed compatible when either side has no type argument. Enabling the `useTypeChecking` option compares the types semantically instead, and infers an `input`'s type from its initial value, so `input('')` paired with `output<number>()` is left alone. A type argument that does not resolve falls back to the text comparison.",
71
149
  };
@@ -67,8 +67,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
67
67
  preferQuerySignals: 'Use the `{{function}}` function instead of the `{{decorator}}` decorator',
68
68
  preferReadonlySignalProperties: 'Properties declared using signals should be marked as `readonly` since they should not be reassigned',
69
69
  },
70
+ defaultOptions: [{ ...DEFAULT_OPTIONS }],
70
71
  },
71
- defaultOptions: [{ ...DEFAULT_OPTIONS }],
72
72
  create(context, [{ preferReadonlySignalProperties = DEFAULT_OPTIONS.preferReadonlySignalProperties, preferInputSignals = DEFAULT_OPTIONS.preferInputSignals, preferQuerySignals = DEFAULT_OPTIONS.preferQuerySignals, additionalSignalCreationFunctions = DEFAULT_OPTIONS.additionalSignalCreationFunctions, useTypeChecking = DEFAULT_OPTIONS.useTypeChecking, },]) {
73
73
  let services;
74
74
  const listener = {};
@@ -19,8 +19,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
19
19
  preferStandalone: `Components, Directives and Pipes should not opt out of standalone. Following this guide is highly recommended: ${RECOMMENDED_GUIDE_URL}`,
20
20
  removeStandaloneFalse: `Quickly remove 'standalone: false'. NOTE - Following this guide is highly recommended: ${RECOMMENDED_GUIDE_URL}`,
21
21
  },
22
+ defaultOptions: [],
22
23
  },
23
- defaultOptions: [],
24
24
  create(context) {
25
25
  const standaloneRuleFactory = (type) => (node) => {
26
26
  const standalone = utils_1.ASTUtils.getDecoratorPropertyValue(node, 'standalone');
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  relativeUrlPrefix: `The ./ and ../ prefix is standard syntax for relative URLs.`,
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  return {
23
23
  [`${utils_1.Selectors.COMPONENT_CLASS_DECORATOR} Property[key.name='templateUrl']`]({ value, }) {
@@ -25,8 +25,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
25
25
  messages: {
26
26
  defineOnPrototype: `The {{ method }} lifecycle method should be defined on the object's prototype. See more at ${ISSUE_LINK}`,
27
27
  },
28
+ defaultOptions: [],
28
29
  },
29
- defaultOptions: [],
30
30
  create(context) {
31
31
  return {
32
32
  [propertyDefinitionSelector](node) {
@@ -44,8 +44,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
44
44
  requireLocalizeMeaning: `$localize tagged messages should contain a meaning. See more at ${STYLE_GUIDE_LINK_METADATA_FOR_TRANSLATION}`,
45
45
  requireLocalizeCustomId: `$localize tagged messages should contain a custom id{{patternMessage}}. See more at ${STYLE_GUIDE_LINK_METADATA_FOR_TRANSLATION}`,
46
46
  },
47
+ defaultOptions: [DEFAULT_OPTIONS],
47
48
  },
48
- defaultOptions: [DEFAULT_OPTIONS],
49
49
  create(context, [{ requireDescription, requireMeaning, requireCustomId }]) {
50
50
  return {
51
51
  TaggedTemplateExpression(taggedTemplateExpression) {
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  runtimeLocalize: `$localize could be called before translations are loaded`,
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  return {
22
22
  TaggedTemplateExpression(taggedTemplateExpression) {
@@ -103,8 +103,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
103
103
  messages: {
104
104
  incorrectOrder: 'Keys in @{{decorator}} decorator should be ordered: {{expectedOrder}}',
105
105
  },
106
+ defaultOptions: [DEFAULT_ORDER],
106
107
  },
107
- defaultOptions: [DEFAULT_ORDER],
108
108
  create(context, [orderConfig]) {
109
109
  function checkContext(node, decoratorName) {
110
110
  const expectedOrder = orderConfig[decoratorName];
@@ -15,8 +15,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
15
15
  messages: {
16
16
  lifecycleMethodsNotSorted: `Lifecycle Methods are not declared in order of execution`,
17
17
  },
18
+ defaultOptions: [],
18
19
  },
19
- defaultOptions: [],
20
20
  create(context) {
21
21
  const isBefore = (method1, method2) => {
22
22
  const methodIndex1 = utils_1.ASTUtils.angularLifecycleMethodsOrdered.indexOf(utils_1.ASTUtils.getMethodName(method1));
@@ -16,8 +16,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
16
16
  messages: {
17
17
  useComponentSelector: 'The selector of the component is mandatory',
18
18
  },
19
+ defaultOptions: [],
19
20
  },
20
- defaultOptions: [],
21
21
  create(context) {
22
22
  return {
23
23
  [utils_1.Selectors.COMPONENT_CLASS_DECORATOR](node) {
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  useComponentViewEncapsulation: `Using \`${VIEW_ENCAPSULATION_NONE}\` makes your styles global, which may have an unintended effect`,
19
19
  suggestRemoveViewEncapsulationNone: `Remove \`${VIEW_ENCAPSULATION_NONE}\``,
20
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  const sourceCode = context.sourceCode;
25
25
  return {
@@ -35,8 +35,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
35
35
  useInjectableProvidedIn: `The \`${METADATA_PROPERTY_NAME}\` property is mandatory for \`Injectables\``,
36
36
  suggestInjector: `Use \`${METADATA_PROPERTY_NAME}: '{{injector}}'\``,
37
37
  },
38
+ defaultOptions: [DEFAULT_OPTIONS],
38
39
  },
39
- defaultOptions: [DEFAULT_OPTIONS],
40
40
  create(context, [{ ignoreClassNamePattern, allowProvidedInNull }]) {
41
41
  const injectableClassDecorator = `ClassDeclaration:not([id.name=${ignoreClassNamePattern}]):not(:has(TSClassImplements:matches([expression.property.name='HttpInterceptor'], [expression.name='HttpInterceptor']))) > Decorator[expression.callee.name="Injectable"]`;
42
42
  const providedInMetadataProperty = utils_1.Selectors.metadataProperty(METADATA_PROPERTY_NAME);
@@ -17,8 +17,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
17
17
  useLifecycleInterface: `Lifecycle interface '{{interfaceName}}' should be implemented for method '{{methodName}}'. (${STYLE_GUIDE_LINK})`,
18
18
  },
19
19
  fixable: 'code',
20
+ defaultOptions: [],
20
21
  },
21
- defaultOptions: [],
22
22
  create(context) {
23
23
  const angularLifecycleMethodsPattern = (0, utils_1.toPattern)([
24
24
  ...utils_1.ASTUtils.ANGULAR_LIFECYCLE_METHODS,
@@ -18,8 +18,8 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  messages: {
19
19
  usePipeTransformInterface: `Pipes should implement \`${PIPE_TRANSFORM}\` interface`,
20
20
  },
21
+ defaultOptions: [],
21
22
  },
22
- defaultOptions: [],
23
23
  create(context) {
24
24
  return {
25
25
  [`ClassDeclaration:not(:has(TSClassImplements:matches([expression.name='${PIPE_TRANSFORM}'], [expression.property.name='${PIPE_TRANSFORM}']))) > Decorator[expression.callee.name='Pipe']`]({ parent: classDeclaration, }) {
@@ -1 +1 @@
1
- {"version":3,"file":"create-eslint-rule.d.ts","sourceRoot":"","sources":["../../src/utils/create-eslint-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAiCD,eAAO,MAAM,gBAAgB;;CAG5B,CAAC"}
1
+ {"version":3,"file":"create-eslint-rule.d.ts","sourceRoot":"","sources":["../../src/utils/create-eslint-rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB;;CAG5B,CAAC"}
@@ -2,27 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createESLintRule = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
- /**
6
- * We need to patch the RuleCreator in order to preserve the defaultOptions
7
- * to use as part of documentation generation.
8
- */
9
- const patchedRuleCreator = (urlCreator) => {
10
- return function createRule({ name, meta, defaultOptions, create }) {
11
- const resolvedDefaultOptions = (defaultOptions ?? []);
12
- return {
13
- name,
14
- meta: Object.assign(Object.assign({}, meta), {
15
- docs: Object.assign(Object.assign({}, meta.docs), {
16
- url: urlCreator(name),
17
- }),
18
- }),
19
- defaultOptions: resolvedDefaultOptions,
20
- create(context) {
21
- const optionsWithDefault = utils_1.ESLintUtils.applyDefault(resolvedDefaultOptions, context.options);
22
- return create(context, optionsWithDefault);
23
- },
24
- };
25
- };
26
- };
27
- patchedRuleCreator.withoutDocs = utils_1.ESLintUtils.RuleCreator.withoutDocs;
28
- exports.createESLintRule = patchedRuleCreator((ruleName) => `https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/${ruleName}.md`);
5
+ exports.createESLintRule = utils_1.ESLintUtils.RuleCreator((ruleName) => `https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/${ruleName}.md`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin",
3
- "version": "22.2.1-alpha.1",
3
+ "version": "22.2.1-alpha.11",
4
4
  "description": "ESLint plugin for Angular applications, following https://angular.dev/style-guide",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -19,12 +19,12 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "dependencies": {
22
- "@angular-eslint/bundled-angular-compiler": "22.2.1-alpha.1",
23
- "@angular-eslint/utils": "22.2.1-alpha.1",
22
+ "@angular-eslint/bundled-angular-compiler": "22.2.1-alpha.11",
23
+ "@angular-eslint/utils": "22.2.1-alpha.11",
24
24
  "ts-api-utils": "^2.1.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@angular-eslint/test-utils": "22.2.1-alpha.1"
27
+ "@angular-eslint/test-utils": "22.2.1-alpha.11"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@typescript-eslint/utils": "^8.0.0",