@angular-eslint/eslint-plugin 20.5.3-alpha.3 → 20.5.3-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -74,12 +74,12 @@ declare const _default: {
74
74
  rules: {
75
75
  "component-class-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"componentClassSuffix", import("./rules/component-class-suffix").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
76
76
  "component-max-inline-declarations": import("@typescript-eslint/utils/ts-eslint").RuleModule<"componentMaxInlineDeclarations", import("./rules/component-max-inline-declarations").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
77
- "component-selector": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/component-selector").MessageIds, import("@angular-eslint/utils/dist/eslint-plugin/selector-utils").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
77
+ "component-selector": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/component-selector").MessageIds, import("@angular-eslint/utils/dist/eslint-plugin/selector-utils").RuleOptions, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
78
78
  "consistent-component-styles": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/consistent-component-styles").MessageIds, import("./rules/consistent-component-styles").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
79
79
  "contextual-decorator": import("@typescript-eslint/utils/ts-eslint").RuleModule<"contextualDecorator", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
80
80
  "contextual-lifecycle": import("@typescript-eslint/utils/ts-eslint").RuleModule<"contextualLifecycle", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
81
81
  "directive-class-suffix": import("@typescript-eslint/utils/ts-eslint").RuleModule<"directiveClassSuffix", import("./rules/directive-class-suffix").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
82
- "directive-selector": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/directive-selector").MessageIds, import("@angular-eslint/utils/dist/eslint-plugin/selector-utils").Options, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
82
+ "directive-selector": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/directive-selector").MessageIds, import("@angular-eslint/utils/dist/eslint-plugin/selector-utils").RuleOptions, import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
83
83
  "no-async-lifecycle-method": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noAsyncLifecycleMethod", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
84
84
  "no-attribute-decorator": import("@typescript-eslint/utils/ts-eslint").RuleModule<"noAttributeDecorator", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
85
85
  "no-conflicting-lifecycle": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/no-conflicting-lifecycle").MessageIds, [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -1,8 +1,8 @@
1
1
  import { SelectorUtils } from '@angular-eslint/utils';
2
- export type Options = SelectorUtils.Options;
2
+ export type Options = SelectorUtils.RuleOptions;
3
3
  export type MessageIds = 'prefixFailure' | 'styleFailure' | 'styleAndPrefixFailure' | 'typeFailure' | 'shadowDomEncapsulatedStyleFailure';
4
4
  export declare const RULE_NAME = "component-selector";
5
- declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, SelectorUtils.Options, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, SelectorUtils.RuleOptions, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
6
  export default _default;
7
7
  export declare const RULE_DOCS_EXTENSION: {
8
8
  rationale: string;
@@ -1 +1 @@
1
- {"version":3,"file":"component-selector.d.ts","sourceRoot":"","sources":["../../src/rules/component-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACd,MAAM,uBAAuB,CAAC;AAK/B,MAAM,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC;AAC5C,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,cAAc,GACd,uBAAuB,GACvB,aAAa,GACb,mCAAmC,CAAC;AACxC,eAAO,MAAM,SAAS,uBAAuB,CAAC;;AAS9C,wBAyHG;AAiBH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
1
+ {"version":3,"file":"component-selector.d.ts","sourceRoot":"","sources":["../../src/rules/component-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACd,MAAM,uBAAuB,CAAC;AAK/B,MAAM,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC;AAChD,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,cAAc,GACd,uBAAuB,GACvB,aAAa,GACb,mCAAmC,CAAC;AACxC,eAAO,MAAM,SAAS,uBAAuB,CAAC;;AAS9C,wBAoMG;AAiBH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -18,35 +18,70 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
18
18
  },
19
19
  schema: [
20
20
  {
21
- type: 'object',
22
- properties: {
23
- type: {
24
- oneOf: [
25
- { type: 'string' },
26
- {
27
- type: 'array',
28
- items: {
21
+ oneOf: [
22
+ // Single config object
23
+ {
24
+ type: 'object',
25
+ properties: {
26
+ type: {
27
+ oneOf: [
28
+ { type: 'string' },
29
+ {
30
+ type: 'array',
31
+ items: {
32
+ type: 'string',
33
+ enum: [
34
+ utils_1.SelectorUtils.OPTION_TYPE_ELEMENT,
35
+ utils_1.SelectorUtils.OPTION_TYPE_ATTRIBUTE,
36
+ ],
37
+ },
38
+ },
39
+ ],
40
+ },
41
+ prefix: {
42
+ oneOf: [{ type: 'string' }, { type: 'array' }],
43
+ },
44
+ style: {
45
+ type: 'string',
46
+ enum: [
47
+ utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
48
+ utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
49
+ ],
50
+ },
51
+ },
52
+ additionalProperties: false,
53
+ },
54
+ // Array of 1-2 config objects
55
+ {
56
+ type: 'array',
57
+ items: {
58
+ type: 'object',
59
+ properties: {
60
+ type: {
29
61
  type: 'string',
30
62
  enum: [
31
63
  utils_1.SelectorUtils.OPTION_TYPE_ELEMENT,
32
64
  utils_1.SelectorUtils.OPTION_TYPE_ATTRIBUTE,
33
65
  ],
34
66
  },
67
+ prefix: {
68
+ oneOf: [{ type: 'string' }, { type: 'array' }],
69
+ },
70
+ style: {
71
+ type: 'string',
72
+ enum: [
73
+ utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
74
+ utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
75
+ ],
76
+ },
35
77
  },
36
- ],
37
- },
38
- prefix: {
39
- oneOf: [{ type: 'string' }, { type: 'array' }],
78
+ additionalProperties: false,
79
+ required: ['type'],
80
+ },
81
+ minItems: 1,
82
+ maxItems: 2,
40
83
  },
41
- style: {
42
- type: 'string',
43
- enum: [
44
- utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
45
- utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
46
- ],
47
- },
48
- },
49
- additionalProperties: false,
84
+ ],
50
85
  },
51
86
  ],
52
87
  messages: {
@@ -64,26 +99,60 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
64
99
  style: '',
65
100
  },
66
101
  ],
67
- create(context, [{ type, prefix, style }]) {
102
+ create(context, [options]) {
103
+ // Normalize options to a consistent format using shared utility
104
+ const configByType = utils_1.SelectorUtils.normalizeOptionsToConfigs(options);
68
105
  return {
69
106
  [utils_1.Selectors.COMPONENT_CLASS_DECORATOR](node) {
70
107
  const rawSelectors = utils_1.ASTUtils.getDecoratorPropertyValue(node, 'selector');
71
108
  if (!rawSelectors) {
72
109
  return;
73
110
  }
111
+ // Parse selectors once for reuse
112
+ const parsedSelectors = utils_1.SelectorUtils.parseSelectorNode(rawSelectors);
113
+ if (!parsedSelectors || parsedSelectors.length === 0) {
114
+ return;
115
+ }
116
+ // For multiple configs, determine the actual selector type
117
+ let applicableConfig = null;
118
+ if (configByType.size > 1) {
119
+ // Multiple configs - need to determine which one applies
120
+ const actualType = utils_1.SelectorUtils.getActualSelectorType(rawSelectors);
121
+ if (!actualType) {
122
+ return;
123
+ }
124
+ const config = configByType.get(actualType);
125
+ if (!config) {
126
+ // No config defined for this selector type
127
+ return;
128
+ }
129
+ applicableConfig = config;
130
+ }
131
+ else {
132
+ // Single config or single type extracted from array
133
+ const firstEntry = configByType.entries().next();
134
+ if (!firstEntry.done) {
135
+ applicableConfig = firstEntry.value[1];
136
+ }
137
+ }
138
+ if (!applicableConfig) {
139
+ return;
140
+ }
141
+ const { type, prefix, style } = applicableConfig;
74
142
  const isValidOptions = utils_1.SelectorUtils.checkValidOptions(type, prefix, style);
75
143
  if (!isValidOptions) {
76
144
  return;
77
145
  }
78
- // override `style` for ShadowDom-encapsulated components. See https://github.com/angular-eslint/angular-eslint/issues/534.
146
+ // Override `style` for ShadowDom-encapsulated components. See https://github.com/angular-eslint/angular-eslint/issues/534.
79
147
  const overrideStyle = style !== utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE &&
80
148
  hasEncapsulationShadowDomProperty(node)
81
149
  ? utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE
82
150
  : style;
83
- const hasExpectedSelector = utils_1.SelectorUtils.checkSelector(rawSelectors, type, (0, utils_1.arrayify)(prefix), overrideStyle);
151
+ const hasExpectedSelector = utils_1.SelectorUtils.checkSelector(rawSelectors, type, (0, utils_1.arrayify)(prefix), overrideStyle, parsedSelectors);
84
152
  if (hasExpectedSelector === null) {
85
153
  return;
86
154
  }
155
+ // Component-specific validation logic (includes styleAndPrefixFailure)
87
156
  if (!hasExpectedSelector.hasExpectedType) {
88
157
  utils_1.SelectorUtils.reportTypeError(rawSelectors, type, context);
89
158
  }
@@ -1,8 +1,8 @@
1
1
  import { SelectorUtils } from '@angular-eslint/utils';
2
- export type Options = SelectorUtils.Options;
2
+ export type Options = SelectorUtils.RuleOptions;
3
3
  export type MessageIds = 'prefixFailure' | 'styleFailure' | 'typeFailure';
4
4
  export declare const RULE_NAME = "directive-selector";
5
- declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, SelectorUtils.Options, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
5
+ declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, SelectorUtils.RuleOptions, import("../utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
6
6
  export default _default;
7
7
  export declare const RULE_DOCS_EXTENSION: {
8
8
  rationale: string;
@@ -1 +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,aAAa,CAAC,OAAO,CAAC;AAC5C,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,cAAc,GAAG,aAAa,CAAC;AAC1E,eAAO,MAAM,SAAS,uBAAuB,CAAC;;AAK9C,wBAgGG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
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,aAAa,CAAC,WAAW,CAAC;AAChD,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,cAAc,GAAG,aAAa,CAAC;AAC1E,eAAO,MAAM,SAAS,uBAAuB,CAAC;;AAE9C,wBA6KG;AAEH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
@@ -4,51 +4,85 @@ exports.RULE_DOCS_EXTENSION = exports.RULE_NAME = void 0;
4
4
  const utils_1 = require("@angular-eslint/utils");
5
5
  const create_eslint_rule_1 = require("../utils/create-eslint-rule");
6
6
  exports.RULE_NAME = 'directive-selector';
7
- const STYLE_GUIDE_LINK = 'https://angular.dev/style-guide#choosing-directive-selectors';
8
7
  exports.default = (0, create_eslint_rule_1.createESLintRule)({
9
8
  name: exports.RULE_NAME,
10
9
  meta: {
11
10
  type: 'suggestion',
12
11
  docs: {
13
- description: `Directive selectors should follow given naming rules. See more at ${STYLE_GUIDE_LINK}.`,
12
+ description: 'Directive selectors should follow given naming rules. See more at https://angular.dev/style-guide#choosing-directive-selectors.',
14
13
  },
15
14
  schema: [
16
15
  {
17
- type: 'object',
18
- properties: {
19
- type: {
20
- oneOf: [
21
- { type: 'string' },
22
- {
23
- type: 'array',
24
- items: {
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
+ additionalProperties: false,
48
+ },
49
+ // Array of 1-2 config objects
50
+ {
51
+ type: 'array',
52
+ items: {
53
+ type: 'object',
54
+ properties: {
55
+ type: {
25
56
  type: 'string',
26
57
  enum: [
27
58
  utils_1.SelectorUtils.OPTION_TYPE_ELEMENT,
28
59
  utils_1.SelectorUtils.OPTION_TYPE_ATTRIBUTE,
29
60
  ],
30
61
  },
62
+ prefix: {
63
+ oneOf: [{ type: 'string' }, { type: 'array' }],
64
+ },
65
+ style: {
66
+ type: 'string',
67
+ enum: [
68
+ utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
69
+ utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
70
+ ],
71
+ },
31
72
  },
32
- ],
73
+ additionalProperties: false,
74
+ required: ['type'],
75
+ },
76
+ minItems: 1,
77
+ maxItems: 2,
33
78
  },
34
- prefix: {
35
- oneOf: [{ type: 'string' }, { type: 'array' }],
36
- },
37
- style: {
38
- type: 'string',
39
- enum: [
40
- utils_1.ASTUtils.OPTION_STYLE_CAMEL_CASE,
41
- utils_1.ASTUtils.OPTION_STYLE_KEBAB_CASE,
42
- ],
43
- },
44
- },
45
- additionalProperties: false,
79
+ ],
46
80
  },
47
81
  ],
48
82
  messages: {
49
- prefixFailure: `The selector should start with one of these prefixes: {{prefix}} (${STYLE_GUIDE_LINK})`,
50
- styleFailure: `The selector should be {{style}} (${STYLE_GUIDE_LINK})`,
51
- typeFailure: `The selector should be used as an {{type}} (${STYLE_GUIDE_LINK})`,
83
+ prefixFailure: 'The selector should start with one of these prefixes: {{prefix}}',
84
+ styleFailure: 'The selector should be {{style}}',
85
+ typeFailure: 'The selector should be used as an {{type}}',
52
86
  },
53
87
  },
54
88
  defaultOptions: [
@@ -58,21 +92,55 @@ exports.default = (0, create_eslint_rule_1.createESLintRule)({
58
92
  style: '',
59
93
  },
60
94
  ],
61
- create(context, [{ type, prefix, style }]) {
95
+ create(context, [options]) {
96
+ // Normalize options to a consistent format using shared utility
97
+ const configByType = utils_1.SelectorUtils.normalizeOptionsToConfigs(options);
62
98
  return {
63
99
  [utils_1.Selectors.DIRECTIVE_CLASS_DECORATOR](node) {
64
100
  const rawSelectors = utils_1.ASTUtils.getDecoratorPropertyValue(node, 'selector');
65
101
  if (!rawSelectors) {
66
102
  return;
67
103
  }
104
+ // Parse selectors once for reuse
105
+ const parsedSelectors = utils_1.SelectorUtils.parseSelectorNode(rawSelectors);
106
+ if (!parsedSelectors || parsedSelectors.length === 0) {
107
+ return;
108
+ }
109
+ // For multiple configs, determine the actual selector type
110
+ let applicableConfig = null;
111
+ if (configByType.size > 1) {
112
+ // Multiple configs - need to determine which one applies
113
+ const actualType = utils_1.SelectorUtils.getActualSelectorType(rawSelectors);
114
+ if (!actualType) {
115
+ return;
116
+ }
117
+ const config = configByType.get(actualType);
118
+ if (!config) {
119
+ // No config defined for this selector type
120
+ return;
121
+ }
122
+ applicableConfig = config;
123
+ }
124
+ else {
125
+ // Single config or single type extracted from array
126
+ const firstEntry = configByType.entries().next();
127
+ if (!firstEntry.done) {
128
+ applicableConfig = firstEntry.value[1];
129
+ }
130
+ }
131
+ if (!applicableConfig) {
132
+ return;
133
+ }
134
+ const { type, prefix, style } = applicableConfig;
68
135
  const isValidOptions = utils_1.SelectorUtils.checkValidOptions(type, prefix, style);
69
136
  if (!isValidOptions) {
70
137
  return;
71
138
  }
72
- const hasExpectedSelector = utils_1.SelectorUtils.checkSelector(rawSelectors, type, (0, utils_1.arrayify)(prefix), style);
139
+ const hasExpectedSelector = utils_1.SelectorUtils.checkSelector(rawSelectors, type, (0, utils_1.arrayify)(prefix), style, parsedSelectors);
73
140
  if (hasExpectedSelector === null) {
74
141
  return;
75
142
  }
143
+ // Directive-specific validation logic (simpler than component)
76
144
  if (!hasExpectedSelector.hasExpectedType) {
77
145
  utils_1.SelectorUtils.reportTypeError(rawSelectors, type, context);
78
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-eslint/eslint-plugin",
3
- "version": "20.5.3-alpha.3",
3
+ "version": "20.5.3-alpha.5",
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,11 +19,11 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "ts-api-utils": "^2.1.0",
22
- "@angular-eslint/bundled-angular-compiler": "20.5.3-alpha.3",
23
- "@angular-eslint/utils": "20.5.3-alpha.3"
22
+ "@angular-eslint/bundled-angular-compiler": "20.5.3-alpha.5",
23
+ "@angular-eslint/utils": "20.5.3-alpha.5"
24
24
  },
25
25
  "devDependencies": {
26
- "@angular-eslint/test-utils": "20.5.3-alpha.3"
26
+ "@angular-eslint/test-utils": "20.5.3-alpha.5"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@typescript-eslint/utils": "^7.11.0 || ^8.0.0",