@angular-eslint/eslint-plugin 22.0.1-alpha.15 → 22.0.1-alpha.16
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/README.md +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/rules/prefer-service-decorator.d.ts +11 -0
- package/dist/rules/prefer-service-decorator.d.ts.map +1 -0
- package/dist/rules/prefer-service-decorator.js +101 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -74,6 +74,7 @@ The premade flat configs that combine these rules are provided by the umbrella [
|
|
|
74
74
|
| [`prefer-on-push-component-change-detection`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-on-push-component-change-detection.md) | Ensures components do not opt out of the default `ChangeDetectionStrategy.OnPush` change detection strategy | :white_check_mark: | | :bulb: |
|
|
75
75
|
| [`prefer-output-emitter-ref`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-output-emitter-ref.md) | Use `OutputEmitterRef` instead of `@Output()` | | | |
|
|
76
76
|
| [`prefer-output-readonly`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-output-readonly.md) | Prefer to declare `@Output`, `OutputEmitterRef` and `OutputRef` as `readonly` since they are not supposed to be reassigned | | | :bulb: |
|
|
77
|
+
| [`prefer-service-decorator`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-service-decorator.md) | Prefer the `@Service()` decorator over `@Injectable({ providedIn: 'root' })` | | :wrench: | |
|
|
77
78
|
| [`prefer-signal-model`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-signal-model.md) | Use `model` instead of `input` and `output` for two-way bindings | | :wrench: | |
|
|
78
79
|
| [`prefer-signals`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-signals.md) | Use readonly signals instead of `@Input()`, `@ViewChild()` and other legacy decorators | | :wrench: | |
|
|
79
80
|
| [`prefer-standalone`](https://github.com/angular-eslint/angular-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-standalone.md) | Ensures Components, Directives and Pipes do not opt out of standalone. | :white_check_mark: | | :bulb: |
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,9 @@ declare const _default: {
|
|
|
102
102
|
"prefer-output-readonly": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/prefer-output-readonly").MessageIds, [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
103
103
|
name: string;
|
|
104
104
|
};
|
|
105
|
+
"prefer-service-decorator": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferServiceDecorator", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
106
|
+
name: string;
|
|
107
|
+
};
|
|
105
108
|
"prefer-signal-model": import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferSignalModel", [], import("./utils/create-eslint-rule").RuleDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
106
109
|
name: string;
|
|
107
110
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoJA,kBAqDE"}
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ const prefer_host_metadata_property_1 = __importStar(require("./rules/prefer-hos
|
|
|
61
61
|
const prefer_on_push_component_change_detection_1 = __importStar(require("./rules/prefer-on-push-component-change-detection"));
|
|
62
62
|
const prefer_output_emitter_ref_1 = __importStar(require("./rules/prefer-output-emitter-ref"));
|
|
63
63
|
const prefer_output_readonly_1 = __importStar(require("./rules/prefer-output-readonly"));
|
|
64
|
+
const prefer_service_decorator_1 = __importStar(require("./rules/prefer-service-decorator"));
|
|
64
65
|
const prefer_signal_model_1 = __importStar(require("./rules/prefer-signal-model"));
|
|
65
66
|
const prefer_inject_1 = __importStar(require("./rules/prefer-inject"));
|
|
66
67
|
const prefer_signals_1 = __importStar(require("./rules/prefer-signals"));
|
|
@@ -116,6 +117,7 @@ module.exports = {
|
|
|
116
117
|
[prefer_on_push_component_change_detection_1.RULE_NAME]: prefer_on_push_component_change_detection_1.default,
|
|
117
118
|
[prefer_output_emitter_ref_1.RULE_NAME]: prefer_output_emitter_ref_1.default,
|
|
118
119
|
[prefer_output_readonly_1.RULE_NAME]: prefer_output_readonly_1.default,
|
|
120
|
+
[prefer_service_decorator_1.RULE_NAME]: prefer_service_decorator_1.default,
|
|
119
121
|
[prefer_signal_model_1.RULE_NAME]: prefer_signal_model_1.default,
|
|
120
122
|
[prefer_signals_1.RULE_NAME]: prefer_signals_1.default,
|
|
121
123
|
[prefer_standalone_1.RULE_NAME]: prefer_standalone_1.default,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Options = [];
|
|
2
|
+
export type MessageIds = 'preferServiceDecorator';
|
|
3
|
+
export declare const RULE_NAME = "prefer-service-decorator";
|
|
4
|
+
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferServiceDecorator", [], 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=prefer-service-decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-service-decorator.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-service-decorator.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,OAAO,GAAG,EAAE,CAAC;AAEzB,MAAM,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAElD,eAAO,MAAM,SAAS,6BAA6B,CAAC;;;;AAEpD,wBAwFG;AA0DH,eAAO,MAAM,mBAAmB;;CAG/B,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
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 = 'prefer-service-decorator';
|
|
8
|
+
exports.default = (0, create_eslint_rule_1.createESLintRule)({
|
|
9
|
+
name: exports.RULE_NAME,
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'suggestion',
|
|
12
|
+
docs: {
|
|
13
|
+
description: "Prefer the `@Service()` decorator over `@Injectable({ providedIn: 'root' })`",
|
|
14
|
+
},
|
|
15
|
+
fixable: 'code',
|
|
16
|
+
schema: [],
|
|
17
|
+
messages: {
|
|
18
|
+
preferServiceDecorator: "Use the `@Service()` decorator instead of `@Injectable({ providedIn: 'root' })`",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
return {
|
|
24
|
+
[utils_1.Selectors.INJECTABLE_CLASS_DECORATOR](node) {
|
|
25
|
+
const { expression } = node;
|
|
26
|
+
if (!utils_1.ASTUtils.isCallExpression(expression) ||
|
|
27
|
+
expression.arguments.length !== 1) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const [argument] = expression.arguments;
|
|
31
|
+
if (!utils_1.ASTUtils.isObjectExpression(argument)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const migration = getMetadataMigration(argument);
|
|
35
|
+
if (!migration) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
context.report({
|
|
39
|
+
node,
|
|
40
|
+
messageId: 'preferServiceDecorator',
|
|
41
|
+
fix: (fixer) => {
|
|
42
|
+
const fixes = [
|
|
43
|
+
// `@Injectable(...)` => `@Service(...)`.
|
|
44
|
+
fixer.replaceText(expression.callee, 'Service'),
|
|
45
|
+
// Migrate the `Injectable` import to `Service`.
|
|
46
|
+
...utils_1.RuleFixes.getImportReplaceFix({
|
|
47
|
+
fixer,
|
|
48
|
+
fromName: 'Injectable',
|
|
49
|
+
moduleName: '@angular/core',
|
|
50
|
+
node,
|
|
51
|
+
sourceCode: context.sourceCode,
|
|
52
|
+
toName: 'Service',
|
|
53
|
+
}),
|
|
54
|
+
];
|
|
55
|
+
switch (migration.type) {
|
|
56
|
+
// Only `providedIn: 'root'`, so drop the whole metadata object.
|
|
57
|
+
case 'drop-metadata': {
|
|
58
|
+
fixes.push(fixer.remove(argument));
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
// Keep the factory, but rename `useFactory` => `factory` and drop
|
|
62
|
+
// `providedIn: 'root'` (which `@Service()` implies).
|
|
63
|
+
case 'rewrite-factory': {
|
|
64
|
+
fixes.push(fixer.replaceText(migration.useFactoryProperty.key, 'factory'), utils_1.RuleFixes.getNodeToCommaRemoveFix(context.sourceCode, migration.providedInProperty, fixer));
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return fixes.filter(utils_1.isNotNullOrUndefined);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* `@Service()` only models `providedIn: 'root'` (implicit) and accepts a
|
|
77
|
+
* `factory` (which maps from `useFactory`). Any other provider metadata
|
|
78
|
+
* (`useClass`, `useExisting`, `useValue`, `deps`, ...) has no equivalent, so we
|
|
79
|
+
* bail out and leave such `@Injectable`s untouched for now.
|
|
80
|
+
*/
|
|
81
|
+
function getMetadataMigration(argument) {
|
|
82
|
+
const properties = argument.properties.filter((property) => property.type === utils_2.AST_NODE_TYPES.Property);
|
|
83
|
+
const providedInProperty = properties.find((property) => utils_2.ASTUtils.getPropertyName(property) === 'providedIn');
|
|
84
|
+
const useFactoryProperty = properties.find((property) => utils_2.ASTUtils.getPropertyName(property) === 'useFactory');
|
|
85
|
+
// Bail out unless the only metadata is `providedIn: 'root'` plus an optional
|
|
86
|
+
// `useFactory`.
|
|
87
|
+
if (!providedInProperty ||
|
|
88
|
+
utils_2.ASTUtils.getStaticValue(providedInProperty.value)?.value !==
|
|
89
|
+
'root' ||
|
|
90
|
+
properties.length !==
|
|
91
|
+
[providedInProperty, useFactoryProperty].filter(utils_1.isNotNullOrUndefined)
|
|
92
|
+
.length) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
return useFactoryProperty
|
|
96
|
+
? { type: 'rewrite-factory', providedInProperty, useFactoryProperty }
|
|
97
|
+
: { type: 'drop-metadata' };
|
|
98
|
+
}
|
|
99
|
+
exports.RULE_DOCS_EXTENSION = {
|
|
100
|
+
rationale: "Angular 22 introduced the `@Service()` decorator as a concise shorthand for `@Injectable({ providedIn: 'root' })`, the most common way to declare a tree-shakable, application-wide service. Using `@Service()` removes the boilerplate of the metadata object while expressing the exact same intent. Because `providedIn: 'root'` is exactly what `@Service()` implies, this migration is safe and behavior-preserving: the `providedIn: 'root'` entry is dropped, and a `useFactory` is preserved by renaming it to `@Service()`'s `factory` option. Services that rely on other provider metadata (`useClass`, `useExisting`, `useValue`, `deps`) or a different `providedIn` value (`'platform'`, `'any'`, a specific module) have no `@Service()` equivalent and are intentionally left untouched.",
|
|
101
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-eslint/eslint-plugin",
|
|
3
|
-
"version": "22.0.1-alpha.
|
|
3
|
+
"version": "22.0.1-alpha.16",
|
|
4
4
|
"description": "ESLint plugin for Angular applications, following https://angular.dev/style-guide",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"ts-api-utils": "^2.1.0",
|
|
23
|
-
"@angular-eslint/bundled-angular-compiler": "22.0.1-alpha.
|
|
24
|
-
"@angular-eslint/utils": "22.0.1-alpha.
|
|
23
|
+
"@angular-eslint/bundled-angular-compiler": "22.0.1-alpha.16",
|
|
24
|
+
"@angular-eslint/utils": "22.0.1-alpha.16"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@angular-eslint/test-utils": "22.0.1-alpha.
|
|
27
|
+
"@angular-eslint/test-utils": "22.0.1-alpha.16"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@typescript-eslint/utils": "^8.0.0",
|