angular-eslint-zoneless 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +13 -0
- package/index.d.ts +32 -0
- package/index.js +111 -0
- package/package.json +34 -0
- package/rules/no-content-decorator.d.ts +3 -0
- package/rules/no-content-decorator.js +35 -0
- package/rules/no-detectchanges-testing.d.ts +3 -0
- package/rules/no-detectchanges-testing.js +36 -0
- package/rules/no-eager-change-detection.d.ts +3 -0
- package/rules/no-eager-change-detection.js +35 -0
- package/rules/no-input-decorator.d.ts +3 -0
- package/rules/no-input-decorator.js +34 -0
- package/rules/no-ngaftercontentchecked.d.ts +3 -0
- package/rules/no-ngaftercontentchecked.js +33 -0
- package/rules/no-ngaftercontentinit.d.ts +3 -0
- package/rules/no-ngaftercontentinit.js +33 -0
- package/rules/no-ngafterviewchecked.d.ts +3 -0
- package/rules/no-ngafterviewchecked.js +33 -0
- package/rules/no-ngafterviewinit.d.ts +3 -0
- package/rules/no-ngafterviewinit.js +33 -0
- package/rules/no-ngdocheck.d.ts +3 -0
- package/rules/no-ngdocheck.js +33 -0
- package/rules/no-ngonchanges.d.ts +3 -0
- package/rules/no-ngonchanges.js +33 -0
- package/rules/no-ngondestroy.d.ts +3 -0
- package/rules/no-ngondestroy.js +33 -0
- package/rules/no-ngoninit.d.ts +3 -0
- package/rules/no-ngoninit.js +33 -0
- package/rules/no-ngzone.d.ts +3 -0
- package/rules/no-ngzone.js +31 -0
- package/rules/no-output-decorator.d.ts +3 -0
- package/rules/no-output-decorator.js +34 -0
- package/rules/no-providezonechangedetection.d.ts +3 -0
- package/rules/no-providezonechangedetection.js +33 -0
- package/rules/no-subscribe-in-component-constructor.d.ts +3 -0
- package/rules/no-subscribe-in-component-constructor.js +35 -0
- package/rules/no-view-decorator.d.ts +3 -0
- package/rules/no-view-decorator.js +35 -0
- package/rules/no-zonejs-import.d.ts +3 -0
- package/rules/no-zonejs-import.js +31 -0
- package/rules/no-zonejs-testing-functions.d.ts +3 -0
- package/rules/no-zonejs-testing-functions.js +43 -0
- package/utils/angular-class-decorator.d.ts +19 -0
- package/utils/angular-class-decorator.js +47 -0
- package/utils/ast-traversal.d.ts +25 -0
- package/utils/ast-traversal.js +36 -0
- package/utils/in-constructor.d.ts +2 -0
- package/utils/in-constructor.js +23 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cyrille Tuzi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# angular-eslint-zoneless
|
|
2
|
+
|
|
3
|
+
ESLint rules for Angular zoneless.
|
|
4
|
+
|
|
5
|
+
**Checks that a zoneless application does not use zone.js-based features and that signals/resources patterns are used, for example:**
|
|
6
|
+
- no zone.js import and provider
|
|
7
|
+
- no zone.js testing functions like `fakeAsync()`
|
|
8
|
+
- no `ChangeDectectionStrategy.Eager`
|
|
9
|
+
- no `NgZone`
|
|
10
|
+
- no `@Input()` and other decorators, to enforce `input()` and other signal equivalents
|
|
11
|
+
- no `ngOnInit()` and other component lifecycle methods, to enforce using signals and resources patterns
|
|
12
|
+
|
|
13
|
+
[The documentation is available on GitHub.](https://github.com/cyrilletuzi/angular-eslint-zoneless)
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ConfigObject } from "@eslint/core";
|
|
2
|
+
declare const plugin: {
|
|
3
|
+
configs: {
|
|
4
|
+
readonly recommended: ConfigObject<import("@eslint/core").RulesConfig>;
|
|
5
|
+
};
|
|
6
|
+
meta: {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
};
|
|
10
|
+
rules: {
|
|
11
|
+
"no-zonejs-import": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
12
|
+
"no-providezonechangedetection": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
13
|
+
"no-eager-change-detection": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
14
|
+
"no-ngoninit": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
15
|
+
"no-ngdocheck": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
16
|
+
"no-ngonchanges": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
17
|
+
"no-ngaftercontentinit": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
18
|
+
"no-ngaftercontentchecked": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
19
|
+
"no-ngafterviewinit": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
20
|
+
"no-ngafterviewchecked": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
21
|
+
"no-ngondestroy": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
22
|
+
"no-input-decorator": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
23
|
+
"no-output-decorator": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
24
|
+
"no-content-decorator": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
25
|
+
"no-view-decorator": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
26
|
+
"no-ngzone": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
27
|
+
"no-detectchanges-testing": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
28
|
+
"no-zonejs-testing-functions": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
29
|
+
"no-subscribe-in-component-constructor": import("@eslint/core").RuleDefinition<import("@eslint/core").RuleDefinitionTypeOptions>;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export = plugin;
|
package/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
const noContentDecorator = __importStar(require("./rules/no-content-decorator.js"));
|
|
36
|
+
const noDetectchangesTesting = __importStar(require("./rules/no-detectchanges-testing.js"));
|
|
37
|
+
const noEagerChangeDetection = __importStar(require("./rules/no-eager-change-detection.js"));
|
|
38
|
+
const noInputDecorator = __importStar(require("./rules/no-input-decorator.js"));
|
|
39
|
+
const noNgaftercontentchecked = __importStar(require("./rules/no-ngaftercontentchecked.js"));
|
|
40
|
+
const noNgaftercontentinit = __importStar(require("./rules/no-ngaftercontentinit.js"));
|
|
41
|
+
const noNgafterviewchecked = __importStar(require("./rules/no-ngafterviewchecked.js"));
|
|
42
|
+
const noNgafterviewinit = __importStar(require("./rules/no-ngafterviewinit.js"));
|
|
43
|
+
const noNgdocheck = __importStar(require("./rules/no-ngdocheck.js"));
|
|
44
|
+
const noNgonchanges = __importStar(require("./rules/no-ngonchanges.js"));
|
|
45
|
+
const noNgondestroy = __importStar(require("./rules/no-ngondestroy.js"));
|
|
46
|
+
const noNgoninit = __importStar(require("./rules/no-ngoninit.js"));
|
|
47
|
+
const noNgzone = __importStar(require("./rules/no-ngzone.js"));
|
|
48
|
+
const noOutputDecorator = __importStar(require("./rules/no-output-decorator.js"));
|
|
49
|
+
const noProvidezonechangedetection = __importStar(require("./rules/no-providezonechangedetection.js"));
|
|
50
|
+
const noSubscribeInComponentConstructor = __importStar(require("./rules/no-subscribe-in-component-constructor.js"));
|
|
51
|
+
const noViewDecorator = __importStar(require("./rules/no-view-decorator.js"));
|
|
52
|
+
const noZonejsImport = __importStar(require("./rules/no-zonejs-import.js"));
|
|
53
|
+
const noZonejsTestingFunctions = __importStar(require("./rules/no-zonejs-testing-functions.js"));
|
|
54
|
+
const { name, version } =
|
|
55
|
+
// importing here would bypass the tsconfig `"rootDir": "src"`
|
|
56
|
+
require("./package.json");
|
|
57
|
+
const plugin = {
|
|
58
|
+
configs: {
|
|
59
|
+
get recommended() {
|
|
60
|
+
return recommended;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
meta: { name, version },
|
|
64
|
+
rules: {
|
|
65
|
+
[noZonejsImport.ruleName]: noZonejsImport.ruleDefinition,
|
|
66
|
+
[noProvidezonechangedetection.ruleName]: noProvidezonechangedetection.ruleDefinition,
|
|
67
|
+
[noEagerChangeDetection.ruleName]: noEagerChangeDetection.ruleDefinition,
|
|
68
|
+
[noNgoninit.ruleName]: noNgoninit.ruleDefinition,
|
|
69
|
+
[noNgdocheck.ruleName]: noNgdocheck.ruleDefinition,
|
|
70
|
+
[noNgonchanges.ruleName]: noNgonchanges.ruleDefinition,
|
|
71
|
+
[noNgaftercontentinit.ruleName]: noNgaftercontentinit.ruleDefinition,
|
|
72
|
+
[noNgaftercontentchecked.ruleName]: noNgaftercontentchecked.ruleDefinition,
|
|
73
|
+
[noNgafterviewinit.ruleName]: noNgafterviewinit.ruleDefinition,
|
|
74
|
+
[noNgafterviewchecked.ruleName]: noNgafterviewchecked.ruleDefinition,
|
|
75
|
+
[noNgondestroy.ruleName]: noNgondestroy.ruleDefinition,
|
|
76
|
+
[noInputDecorator.ruleName]: noInputDecorator.ruleDefinition,
|
|
77
|
+
[noOutputDecorator.ruleName]: noOutputDecorator.ruleDefinition,
|
|
78
|
+
[noContentDecorator.ruleName]: noContentDecorator.ruleDefinition,
|
|
79
|
+
[noViewDecorator.ruleName]: noViewDecorator.ruleDefinition,
|
|
80
|
+
[noNgzone.ruleName]: noNgzone.ruleDefinition,
|
|
81
|
+
[noDetectchangesTesting.ruleName]: noDetectchangesTesting.ruleDefinition,
|
|
82
|
+
[noZonejsTestingFunctions.ruleName]: noZonejsTestingFunctions.ruleDefinition,
|
|
83
|
+
[noSubscribeInComponentConstructor.ruleName]: noSubscribeInComponentConstructor.ruleDefinition,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const recommended = {
|
|
87
|
+
plugins: {
|
|
88
|
+
[name]: plugin
|
|
89
|
+
},
|
|
90
|
+
rules: {
|
|
91
|
+
[`${name}/${noZonejsImport.ruleName}`]: "error",
|
|
92
|
+
[`${name}/${noProvidezonechangedetection.ruleName}`]: "error",
|
|
93
|
+
[`${name}/${noEagerChangeDetection.ruleName}`]: "error",
|
|
94
|
+
[`${name}/${noNgoninit.ruleName}`]: "error",
|
|
95
|
+
[`${name}/${noNgdocheck.ruleName}`]: "error",
|
|
96
|
+
[`${name}/${noNgonchanges.ruleName}`]: "error",
|
|
97
|
+
[`${name}/${noNgaftercontentinit.ruleName}`]: "error",
|
|
98
|
+
[`${name}/${noNgaftercontentchecked.ruleName}`]: "error",
|
|
99
|
+
[`${name}/${noNgafterviewinit.ruleName}`]: "error",
|
|
100
|
+
[`${name}/${noNgafterviewchecked.ruleName}`]: "error",
|
|
101
|
+
[`${name}/${noNgondestroy.ruleName}`]: "error",
|
|
102
|
+
[`${name}/${noInputDecorator.ruleName}`]: "error",
|
|
103
|
+
[`${name}/${noOutputDecorator.ruleName}`]: "error",
|
|
104
|
+
[`${name}/${noContentDecorator.ruleName}`]: "error",
|
|
105
|
+
[`${name}/${noViewDecorator.ruleName}`]: "error",
|
|
106
|
+
[`${name}/${noNgzone.ruleName}`]: "error",
|
|
107
|
+
[`${name}/${noDetectchangesTesting.ruleName}`]: "error",
|
|
108
|
+
[`${name}/${noZonejsTestingFunctions.ruleName}`]: "error",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
module.exports = plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "angular-eslint-zoneless",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Angular zoneless lint rules for ESLint",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"eslint"
|
|
8
|
+
],
|
|
9
|
+
"funding": {
|
|
10
|
+
"type": "github",
|
|
11
|
+
"url": "https://github.com/sponsors/cyrilletuzi"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/cyrilletuzi/angular-eslint-zoneless#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/cyrilletuzi/angular-eslint-zoneless/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/cyrilletuzi/angular-eslint-zoneless.git"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Cyrille Tuzi",
|
|
23
|
+
"type": "commonjs",
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./index.d.ts",
|
|
28
|
+
"default": "./index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@typescript-eslint/utils": "^8.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-content-decorator";
|
|
6
|
+
const messageId = "noContentDecorator";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ContentChild()\` and \`ContentChildren()\` should not be used in a zoneless application, use \`contentChild()\` and \`contentChildren()\` instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ContentChild()\` and \`ContentChildren()\` are not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_CONTENT_DECORATOR.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
Decorator(node) {
|
|
23
|
+
if (node.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
24
|
+
node.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
(node.expression.callee.name === "ContentChild" ||
|
|
26
|
+
node.expression.callee.name === "ContentChildren")) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const angular_class_decorator_1 = require("../utils/angular-class-decorator");
|
|
6
|
+
exports.ruleName = "no-detectchanges-testing";
|
|
7
|
+
const messageId = "noDetectchangesTesting";
|
|
8
|
+
exports.ruleDefinition = {
|
|
9
|
+
meta: {
|
|
10
|
+
type: "problem",
|
|
11
|
+
messages: {
|
|
12
|
+
[messageId]: `\`fixture.detectChanges()\` should be avoided in a zoneless application, use \`await fixture.whenStable()\` instead.`,
|
|
13
|
+
},
|
|
14
|
+
docs: {
|
|
15
|
+
description: `Checks that \`fixture.detectChanges()\` is not called.`,
|
|
16
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_DETECTCHANGES_TESTING.md',
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
24
|
+
node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
node.callee.property.name === "detectChanges" &&
|
|
26
|
+
// Report only in tests, otherwise it will report on `ChangeDetectorRef.detectChanges()`
|
|
27
|
+
!(0, angular_class_decorator_1.isInAngularClass)(node, ["Component", "Directive"])) {
|
|
28
|
+
context.report({
|
|
29
|
+
node,
|
|
30
|
+
messageId,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-eager-change-detection";
|
|
6
|
+
const messageId = "noEagerChangeDetection";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ChangeDetectionStrategy.Eager\` and \`ChangeDetectionStrategy.Default\` should not be used in a zoneless application, use \`ChangeDetectionStrategy.OnPush\` instead (the default in Angular >= 22).`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ChangeDetectionStrategy.Eager\` and \`ChangeDetectionStrategy.Default\` are not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_EAGER_CHANGE_DETECTION.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MemberExpression(node) {
|
|
23
|
+
if (node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.object.name === "ChangeDetectionStrategy" &&
|
|
25
|
+
node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
26
|
+
(node.property.name === "Eager" || node.property.name === "Default")) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-input-decorator";
|
|
6
|
+
const messageId = "noInputDecorator";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`Input()\` should not be used in a zoneless application, use \`input()\` instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`Input()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_INPUT_DECORATOR.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
Decorator(node) {
|
|
23
|
+
if (node.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
24
|
+
node.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
node.expression.callee.name === "Input") {
|
|
26
|
+
context.report({
|
|
27
|
+
node,
|
|
28
|
+
messageId,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngaftercontentchecked";
|
|
6
|
+
const messageId = "noNgaftercontentchecked";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngAfterContentChecked()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngAfterContentChecked()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGAFTERCONTENTCHECKED.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngAfterContentChecked") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngaftercontentinit";
|
|
6
|
+
const messageId = "noNgaftercontentinit";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngAfterContentInit()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngAfterContentInit()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGAFTERCONTENTINIT.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngAfterContentInit") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngafterviewchecked";
|
|
6
|
+
const messageId = "noNgafterviewchecked";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngAfterViewChecked()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngAfterViewChecked()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGAFTERVIEWCHECKED.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngAfterViewChecked") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngafterviewinit";
|
|
6
|
+
const messageId = "noNgafterviewinit";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngAfterViewInit()\` should be avoided in a zoneless application, use signals and resources reactivity instead, or when really needed, use \`afterNextRender()\`.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngAfterViewInit()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGAFTERVIEWINIT.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngAfterViewInit") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngdocheck";
|
|
6
|
+
const messageId = "noNgdocheck";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngDoCheck()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngDoCheck()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGDOCHECK.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngDoCheck") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngonchanges";
|
|
6
|
+
const messageId = "noNgonchanges";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngOnChanges()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngOnChanges()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGONCHANGES.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngOnChanges") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngondestroy";
|
|
6
|
+
const messageId = "noNgondestroy";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngOnDestroy()\` should be avoided in a zoneless application, signals and resources destroy is automatic; if really needed, use \`DestroyRef.onDestroy()\`.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngOnDestroy()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGONDESTROY.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngOnDestroy") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-ngoninit";
|
|
6
|
+
const messageId = "noNgoninit";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ngOnInit()\` should be avoided in a zoneless application, use signals and resources reactivity instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ngOnInit()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGONINIT.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
MethodDefinition(node) {
|
|
23
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.key.name === "ngOnInit") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
exports.ruleName = "no-ngzone";
|
|
5
|
+
const messageId = "noNgzone";
|
|
6
|
+
exports.ruleDefinition = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: "problem",
|
|
9
|
+
messages: {
|
|
10
|
+
[messageId]: `\`NgZone()\` is useless and does not work in a zoneless application.`,
|
|
11
|
+
},
|
|
12
|
+
docs: {
|
|
13
|
+
description: `Checks that \`NgZone()\` is not used.`,
|
|
14
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_NGZONE.md',
|
|
15
|
+
recommended: true,
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
},
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
Identifier(node) {
|
|
22
|
+
if (node.name === 'NgZone') {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-output-decorator";
|
|
6
|
+
const messageId = "noOutputDecorator";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`Output()\` should not be used in a zoneless application, use \`output()\` instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`Output()\` is not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_OUTPUT_DECORATOR.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
Decorator(node) {
|
|
23
|
+
if (node.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
24
|
+
node.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
node.expression.callee.name === "Output") {
|
|
26
|
+
context.report({
|
|
27
|
+
node,
|
|
28
|
+
messageId,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-providezonechangedetection";
|
|
6
|
+
const messageId = "noProvidezonechangedetection";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`provideZoneChangeDetection()\` is forbidden in a zoneless application.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`provideZoneChangeDetection()\` is not called.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_PROVIDEZONECHANGEDETECTION.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
24
|
+
node.callee.name === "provideZoneChangeDetection") {
|
|
25
|
+
context.report({
|
|
26
|
+
node,
|
|
27
|
+
messageId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const in_constructor_1 = require("../utils/in-constructor");
|
|
6
|
+
exports.ruleName = "no-subscribe-in-component-constructor";
|
|
7
|
+
const messageId = "noSubscribeInComponentConstructor";
|
|
8
|
+
exports.ruleDefinition = {
|
|
9
|
+
meta: {
|
|
10
|
+
type: "problem",
|
|
11
|
+
messages: {
|
|
12
|
+
[messageId]: `An observable inside a component constructor can generally be managed with \`toSignal()\` or \`rxResource()\` instead.`,
|
|
13
|
+
},
|
|
14
|
+
docs: {
|
|
15
|
+
description: `Checks that observables are not explicitly subscribed in components constructors.`,
|
|
16
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_SUBSCRIBE_IN_COMPONENT_CONSTRUCTOR.md',
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
24
|
+
node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
node.callee.property.name === 'subscribe' &&
|
|
26
|
+
(0, in_constructor_1.isInAngularComponentConstructor)(node)) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-view-decorator";
|
|
6
|
+
const messageId = "noViewDecorator";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `\`ViewChild()\` and \`ViewChildren()\` should not be used in a zoneless application, use \`viewChild()\` and \`viewChildren()\` instead.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that \`ViewChild()\` and \`ViewChildren()\` are not used.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_VIEW_DECORATOR.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
Decorator(node) {
|
|
23
|
+
if (node.expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
24
|
+
node.expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
25
|
+
(node.expression.callee.name === "ViewChild" ||
|
|
26
|
+
node.expression.callee.name === "ViewChildren")) {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
exports.ruleName = "no-zonejs-import";
|
|
5
|
+
const messageId = "noZonejsImport";
|
|
6
|
+
exports.ruleDefinition = {
|
|
7
|
+
meta: {
|
|
8
|
+
type: "problem",
|
|
9
|
+
messages: {
|
|
10
|
+
[messageId]: `Importing zone.js is forbidden in a zoneless application.`,
|
|
11
|
+
},
|
|
12
|
+
docs: {
|
|
13
|
+
description: `Checks that \`zone.js\` is not imported.`,
|
|
14
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_ZONEJS_IMPORT.md',
|
|
15
|
+
recommended: true,
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
},
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
ImportDeclaration(node) {
|
|
22
|
+
if (node.source.value === "zone.js") {
|
|
23
|
+
context.report({
|
|
24
|
+
node,
|
|
25
|
+
messageId,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ruleDefinition = exports.ruleName = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
exports.ruleName = "no-zonejs-testing-functions";
|
|
6
|
+
const messageId = "noZonejsTestingFunctions";
|
|
7
|
+
exports.ruleDefinition = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: "problem",
|
|
10
|
+
messages: {
|
|
11
|
+
[messageId]: `zone.js testing functions (\`fakeAsync()\`, \`discardPeriodicTasks()\`, \`flush()\`, \`flushMicrotasks()\`, \`resetFakeAsyncZone()\`, \`tick()\`, \`waitForAsync()\`) are useless and do not work in a zoneless application.`,
|
|
12
|
+
},
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Checks that zone.js testing functions are not called.`,
|
|
15
|
+
url: 'https://github.com/cyrilletuzi/angular-eslint-zoneless/blob/main/docs/rules/NO_ZONEJS_TESTING_FUNCTIONS.md',
|
|
16
|
+
recommended: true,
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
24
|
+
const testingFunctions = new Set([
|
|
25
|
+
"fakeAsync",
|
|
26
|
+
"discardPeriodicTasks",
|
|
27
|
+
"flush",
|
|
28
|
+
"flushMicrotasks",
|
|
29
|
+
"resetFakeAsyncZone",
|
|
30
|
+
"tick",
|
|
31
|
+
"waitForAsync",
|
|
32
|
+
]);
|
|
33
|
+
if (testingFunctions.has(node.callee.name)) {
|
|
34
|
+
context.report({
|
|
35
|
+
node,
|
|
36
|
+
messageId,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
export type AngularClassDecorator = "Component" | "Directive" | "Injectable" | "NgModule" | "Pipe" | "Service";
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a `ClassDeclaration` has an Angular decorator and returns it.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const classDeclaration = findNearestAncestorOf(
|
|
9
|
+
* node,
|
|
10
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
11
|
+
* );
|
|
12
|
+
*
|
|
13
|
+
* if (classDeclaration && findAngularClassDecorator(classDeclaration)) {
|
|
14
|
+
* return true;
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function findAngularClassDecorator({ decorators }: TSESTree.ClassDeclaration, allowedDecorators?: readonly AngularClassDecorator[]): AngularClassDecorator | undefined;
|
|
19
|
+
export declare function isInAngularClass(node: TSESTree.Node, allowedDecorators?: readonly AngularClassDecorator[]): boolean;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findAngularClassDecorator = findAngularClassDecorator;
|
|
4
|
+
exports.isInAngularClass = isInAngularClass;
|
|
5
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
6
|
+
const ast_traversal_1 = require("./ast-traversal");
|
|
7
|
+
/**
|
|
8
|
+
* Checks if a `ClassDeclaration` has an Angular decorator and returns it.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const classDeclaration = findNearestAncestorOf(
|
|
13
|
+
* node,
|
|
14
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
15
|
+
* );
|
|
16
|
+
*
|
|
17
|
+
* if (classDeclaration && findAngularClassDecorator(classDeclaration)) {
|
|
18
|
+
* return true;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function findAngularClassDecorator({ decorators }, allowedDecorators = [
|
|
23
|
+
"Component", "Directive", "Injectable", "NgModule", "Pipe", "Service",
|
|
24
|
+
]) {
|
|
25
|
+
const angularClassDecorators = new Set(allowedDecorators);
|
|
26
|
+
return decorators
|
|
27
|
+
?.map(({ expression }) => {
|
|
28
|
+
if (utils_1.ASTUtils.isIdentifier(expression)) {
|
|
29
|
+
return expression.name;
|
|
30
|
+
}
|
|
31
|
+
return expression.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
32
|
+
utils_1.ASTUtils.isIdentifier(expression.callee)
|
|
33
|
+
? expression.callee.name
|
|
34
|
+
: undefined;
|
|
35
|
+
})
|
|
36
|
+
.filter((item) => item !== undefined)
|
|
37
|
+
.find((value) => angularClassDecorators.has(value));
|
|
38
|
+
}
|
|
39
|
+
;
|
|
40
|
+
function isInAngularClass(node, allowedDecorators) {
|
|
41
|
+
const classDeclaration = (0, ast_traversal_1.findNearestAncestorOf)(node, (node) => node.type === utils_1.AST_NODE_TYPES.ClassDeclaration);
|
|
42
|
+
if (classDeclaration &&
|
|
43
|
+
findAngularClassDecorator(classDeclaration, allowedDecorators)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type TSESTree } from "@typescript-eslint/utils";
|
|
2
|
+
/**
|
|
3
|
+
* Get the nearest ancestor node of a certain type.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const classDeclaration = getNearestNodeFrom(
|
|
8
|
+
* node,
|
|
9
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
10
|
+
* );
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* With `notInCallback` option enabled, the traversal will stop if it encounters a `CallExpression`.
|
|
14
|
+
* This is needed for some rules because the injection context is lost when inside a callback.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const classDeclaration = getNearestNodeFrom(
|
|
19
|
+
* node,
|
|
20
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
21
|
+
* { notInCallback: true },
|
|
22
|
+
* );
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function findNearestAncestorOf<T extends TSESTree.Node>({ parent }: TSESTree.Node, predicate: (parent: TSESTree.Node) => parent is T): T | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findNearestAncestorOf = findNearestAncestorOf;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
/**
|
|
6
|
+
* Get the nearest ancestor node of a certain type.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const classDeclaration = getNearestNodeFrom(
|
|
11
|
+
* node,
|
|
12
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
13
|
+
* );
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* With `notInCallback` option enabled, the traversal will stop if it encounters a `CallExpression`.
|
|
17
|
+
* This is needed for some rules because the injection context is lost when inside a callback.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const classDeclaration = getNearestNodeFrom(
|
|
22
|
+
* node,
|
|
23
|
+
* (node) => node.type === AST_NODE_TYPES.ClassDeclaration,
|
|
24
|
+
* { notInCallback: true },
|
|
25
|
+
* );
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function findNearestAncestorOf({ parent }, predicate) {
|
|
29
|
+
while (parent && parent.type !== utils_1.AST_NODE_TYPES.Program) {
|
|
30
|
+
if (predicate(parent)) {
|
|
31
|
+
return parent;
|
|
32
|
+
}
|
|
33
|
+
parent = parent.parent;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isInAngularComponentConstructor = isInAngularComponentConstructor;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const angular_class_decorator_1 = require("./angular-class-decorator");
|
|
6
|
+
const ast_traversal_1 = require("./ast-traversal");
|
|
7
|
+
function isInConstructor(node) {
|
|
8
|
+
const methodDefinition = (0, ast_traversal_1.findNearestAncestorOf)(node, (node) => node.type === utils_1.AST_NODE_TYPES.MethodDefinition);
|
|
9
|
+
if (methodDefinition?.kind === "constructor") {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
function isInAngularComponentConstructor(node) {
|
|
15
|
+
if (isInConstructor(node)) {
|
|
16
|
+
const classDeclaration = (0, ast_traversal_1.findNearestAncestorOf)(node, (node) => node.type === utils_1.AST_NODE_TYPES.ClassDeclaration);
|
|
17
|
+
if (classDeclaration &&
|
|
18
|
+
(0, angular_class_decorator_1.findAngularClassDecorator)(classDeclaration, ["Component"])) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|