@spinnaker/eslint-plugin 2026.0.1 → 2026.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/base.config.js +132 -81
- package/eslint-plugin.ts +28 -23
- package/none.config.js +35 -17
- package/package.json +19 -14
- package/rules/api-deprecation.ts +9 -2
- package/rules/api-no-slashes.ts +7 -2
- package/rules/import-from-alias-not-npm.ts +2 -2
- package/rules/import-from-npm-not-alias.ts +2 -2
- package/rules/import-from-npm-not-relative.ts +2 -2
- package/rules/import-relative-within-subpackage.ts +2 -2
- package/rules/migrate-to-mock-http-client.ts +5 -7
- package/rules/ng-no-component-class.ts +1 -2
- package/rules/ng-no-module-export.ts +5 -5
- package/rules/ng-no-require-angularjs.ts +6 -8
- package/rules/ng-no-require-module-deps.ts +9 -9
- package/rules/ng-strictdi.ts +1 -1
- package/rules/prefer-promise-like.ts +3 -3
- package/rules/react2angular-with-error-boundary.ts +6 -5
- package/rules/rest-prefer-static-strings-in-initializer.spec.ts +0 -6
- package/rules/rest-prefer-static-strings-in-initializer.ts +4 -4
- package/utils/angular-rule/angular-rule.js +2 -2
- package/utils/angular-rule/utils.js +2 -1
- package/utils/ast.ts +1 -3
- package/utils/ruleTester.js +3 -3
- package/utils/utils.ts +14 -14
package/README.md
CHANGED
|
@@ -5,19 +5,33 @@ This package is an ESLint plugin containing:
|
|
|
5
5
|
- A base ESLint config
|
|
6
6
|
- Parser configured for typescript
|
|
7
7
|
- A set of default plugins, e.g. `react-hooks` plugin
|
|
8
|
-
- Recommended rule sets, e.g. `prettier
|
|
8
|
+
- Recommended rule sets, e.g. `prettier`, `@typescript-eslint/recommended`
|
|
9
9
|
- Specific from the recommended rule sets are disabled
|
|
10
10
|
- Custom ESLint rules specific to Spinnaker
|
|
11
11
|
|
|
12
12
|
### Use
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
This plugin requires **ESLint 9+** and uses the flat config format.
|
|
15
|
+
|
|
16
|
+
To use the rules, create an `eslint.config.js` containing:
|
|
15
17
|
|
|
16
18
|
```js
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const { defineConfig } = require('eslint/config');
|
|
20
|
+
const spinnakerEslintPlugin = require('@spinnaker/eslint-plugin');
|
|
21
|
+
const { FlatCompat } = require('@eslint/eslintrc');
|
|
22
|
+
const js = require('@eslint/js');
|
|
23
|
+
|
|
24
|
+
const compat = new FlatCompat({
|
|
25
|
+
baseDirectory: __dirname,
|
|
26
|
+
recommendedConfig: js.configs.recommended,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
module.exports = defineConfig([{
|
|
30
|
+
plugins: {
|
|
31
|
+
'@spinnaker': spinnakerEslintPlugin,
|
|
32
|
+
},
|
|
33
|
+
extends: compat.extends('plugin:@spinnaker/base'),
|
|
34
|
+
}]);
|
|
21
35
|
```
|
|
22
36
|
|
|
23
37
|
## Creating a custom lint rule
|
package/base.config.js
CHANGED
|
@@ -1,86 +1,137 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
|
|
39
|
-
'@typescript-eslint/ban-ts-ignore': 'off',
|
|
40
|
-
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
|
|
41
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
42
|
-
'@typescript-eslint/explicit-member-accessibility': 'off',
|
|
43
|
-
'@typescript-eslint/indent': 'off',
|
|
44
|
-
'@typescript-eslint/interface-name-prefix': 'off',
|
|
45
|
-
'@typescript-eslint/no-case-declarations': 'off',
|
|
46
|
-
'@typescript-eslint/no-empty-function': 'off',
|
|
47
|
-
'@typescript-eslint/no-empty-interface': 'off',
|
|
48
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
49
|
-
'@typescript-eslint/no-object-literal-type-assertion': 'off',
|
|
50
|
-
'@typescript-eslint/no-parameter-properties': 'off',
|
|
51
|
-
'@typescript-eslint/no-this-alias': 'off',
|
|
52
|
-
'@typescript-eslint/no-triple-slash-reference': 'off',
|
|
53
|
-
'@typescript-eslint/no-unused-vars': 'off',
|
|
54
|
-
'@typescript-eslint/no-use-before-define': 'off',
|
|
55
|
-
'@typescript-eslint/no-var-requires': 'off', // TODO: turn on once all code is using ES6 imports
|
|
56
|
-
'@typescript-eslint/triple-slash-reference': 'off',
|
|
57
|
-
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
58
|
-
'@typescript-eslint/ban-types': 'off',
|
|
59
|
-
'@typescript-eslint/ban-ts-comment': 'off',
|
|
60
|
-
},
|
|
61
|
-
overrides: [
|
|
62
|
-
{
|
|
63
|
-
files: ['*.js', '*.jsx'],
|
|
64
|
-
rules: {
|
|
65
|
-
'@typescript-eslint/no-use-before-define': 'off',
|
|
1
|
+
const { globalIgnores } = require('eslint/config');
|
|
2
|
+
|
|
3
|
+
const tsParser = require('@typescript-eslint/parser');
|
|
4
|
+
const typescriptEslint = require('@typescript-eslint/eslint-plugin');
|
|
5
|
+
const reactHooks = require('eslint-plugin-react-hooks');
|
|
6
|
+
|
|
7
|
+
// Import rules directly to avoid circular dependency when this config is bundled in the plugin
|
|
8
|
+
// Use a function to get rules lazily
|
|
9
|
+
const getSpinnakerRules = () => require('./index.js').rules;
|
|
10
|
+
|
|
11
|
+
const globals = require('globals');
|
|
12
|
+
const js = require('@eslint/js');
|
|
13
|
+
|
|
14
|
+
const { FlatCompat } = require('@eslint/eslintrc');
|
|
15
|
+
|
|
16
|
+
const compat = new FlatCompat({
|
|
17
|
+
baseDirectory: __dirname,
|
|
18
|
+
recommendedConfig: js.configs.recommended,
|
|
19
|
+
allConfig: js.configs.all,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
module.exports = [
|
|
23
|
+
js.configs.recommended,
|
|
24
|
+
...compat.extends('prettier', 'plugin:@typescript-eslint/recommended'),
|
|
25
|
+
{
|
|
26
|
+
languageOptions: {
|
|
27
|
+
parser: tsParser,
|
|
28
|
+
sourceType: 'module',
|
|
29
|
+
parserOptions: {},
|
|
30
|
+
|
|
31
|
+
globals: {
|
|
32
|
+
...globals.browser,
|
|
33
|
+
...globals.node,
|
|
34
|
+
...globals.jasmine,
|
|
35
|
+
angular: true,
|
|
36
|
+
$: true,
|
|
37
|
+
_: true,
|
|
66
38
|
},
|
|
67
39
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
40
|
+
|
|
41
|
+
plugins: {
|
|
42
|
+
'@typescript-eslint': typescriptEslint,
|
|
43
|
+
'@spinnaker': { rules: getSpinnakerRules() },
|
|
44
|
+
'react-hooks': { rules: reactHooks.rules },
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
rules: {
|
|
48
|
+
'@spinnaker/import-sort': 1,
|
|
49
|
+
'@spinnaker/api-deprecation': 2,
|
|
50
|
+
'@spinnaker/api-no-slashes': 2,
|
|
51
|
+
'@spinnaker/api-no-unused-chaining': 2,
|
|
52
|
+
'@spinnaker/import-from-alias-not-npm': 2,
|
|
53
|
+
'@spinnaker/import-from-npm-not-alias': 2,
|
|
54
|
+
'@spinnaker/import-from-npm-not-relative': 2,
|
|
55
|
+
'@spinnaker/import-from-presentation-not-core': 2,
|
|
56
|
+
'@spinnaker/import-relative-within-subpackage': 2,
|
|
57
|
+
'@spinnaker/migrate-to-mock-http-client': 2,
|
|
58
|
+
'@spinnaker/ng-no-component-class': 2,
|
|
59
|
+
'@spinnaker/ng-no-module-export': 2,
|
|
60
|
+
'@spinnaker/ng-no-require-angularjs': 2,
|
|
61
|
+
'@spinnaker/ng-no-require-module-deps': 2,
|
|
62
|
+
'@spinnaker/ng-strictdi': 'off',
|
|
63
|
+
'@spinnaker/prefer-promise-like': 1,
|
|
64
|
+
'@spinnaker/react2angular-with-error-boundary': 2,
|
|
65
|
+
'@spinnaker/rest-prefer-static-strings-in-initializer': 2,
|
|
66
|
+
indent: 'off',
|
|
67
|
+
'member-ordering': 'off',
|
|
68
|
+
'no-console': [
|
|
69
|
+
'error',
|
|
70
|
+
{
|
|
71
|
+
allow: ['warn', 'error'],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
'no-extra-boolean-cast': 'off',
|
|
75
|
+
'no-prototype-builtins': 'off',
|
|
76
|
+
'one-var': [
|
|
77
|
+
'error',
|
|
78
|
+
{
|
|
79
|
+
initialized: 'never',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
'prefer-rest-params': 'off',
|
|
83
|
+
'prefer-spread': 'off',
|
|
84
|
+
'require-atomic-updates': 'off',
|
|
85
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
86
|
+
'@typescript-eslint/array-type': [
|
|
87
|
+
'error',
|
|
88
|
+
{
|
|
89
|
+
default: 'array-simple',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
'@typescript-eslint/ban-ts-ignore': 'off',
|
|
93
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
94
|
+
'error',
|
|
95
|
+
{
|
|
96
|
+
prefer: 'type-imports',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
100
|
+
'@typescript-eslint/explicit-member-accessibility': 'off',
|
|
101
|
+
'@typescript-eslint/indent': 'off',
|
|
102
|
+
'@typescript-eslint/interface-name-prefix': 'off',
|
|
103
|
+
'@typescript-eslint/no-case-declarations': 'off',
|
|
104
|
+
'@typescript-eslint/no-empty-function': 'off',
|
|
105
|
+
'@typescript-eslint/no-empty-interface': 'off',
|
|
106
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
107
|
+
'@typescript-eslint/no-object-literal-type-assertion': 'off',
|
|
108
|
+
'@typescript-eslint/no-parameter-properties': 'off',
|
|
109
|
+
'@typescript-eslint/no-this-alias': 'off',
|
|
110
|
+
'@typescript-eslint/no-triple-slash-reference': 'off',
|
|
111
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
112
|
+
'@typescript-eslint/no-use-before-define': 'off',
|
|
113
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
114
|
+
'@typescript-eslint/triple-slash-reference': 'off',
|
|
115
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
116
|
+
'@typescript-eslint/ban-types': 'off',
|
|
117
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
118
|
+
'@typescript-eslint/no-require-imports': 'off',
|
|
119
|
+
'@typescript-eslint/no-unused-expressions': 'off',
|
|
120
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
121
|
+
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
73
122
|
},
|
|
74
|
-
],
|
|
75
|
-
env: {
|
|
76
|
-
browser: true,
|
|
77
|
-
node: true,
|
|
78
|
-
es6: true,
|
|
79
|
-
jasmine: true,
|
|
80
123
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
124
|
+
{
|
|
125
|
+
files: ['**/*.js', '**/*.jsx'],
|
|
126
|
+
rules: {
|
|
127
|
+
'@typescript-eslint/no-use-before-define': 'off',
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
132
|
+
rules: {
|
|
133
|
+
'no-undef': 'off',
|
|
134
|
+
},
|
|
85
135
|
},
|
|
86
|
-
|
|
136
|
+
globalIgnores(['**/*.spec.*', './template/**/*']),
|
|
137
|
+
];
|
package/eslint-plugin.ts
CHANGED
|
@@ -17,30 +17,35 @@ import preferPromiseLike from './rules/prefer-promise-like';
|
|
|
17
17
|
import react2angularWithErrorBoundary from './rules/react2angular-with-error-boundary';
|
|
18
18
|
import restPreferStaticStringsInInitializer from './rules/rest-prefer-static-strings-in-initializer';
|
|
19
19
|
|
|
20
|
+
const rules = {
|
|
21
|
+
'api-deprecation': apiDeprecation,
|
|
22
|
+
'api-no-slashes': apiNoSlashes,
|
|
23
|
+
'api-no-unused-chaining': apiNoUnusedChaining,
|
|
24
|
+
'import-from-alias-not-npm': importFromAliasNotNpm,
|
|
25
|
+
'import-from-npm-not-alias': importFromNpmNotAlias,
|
|
26
|
+
'import-from-npm-not-relative': importFromNpmNotRelative,
|
|
27
|
+
'import-from-presentation-not-core': importFromPresentationNotCore,
|
|
28
|
+
'import-relative-within-subpackage': importRelativeWithinSubpackage,
|
|
29
|
+
'import-sort': importSort,
|
|
30
|
+
'migrate-to-mock-http-client': migrateToMockHttpClient,
|
|
31
|
+
'ng-no-component-class': ngNoComponentClass,
|
|
32
|
+
'ng-no-module-export': ngNoModuleExport,
|
|
33
|
+
'ng-no-require-angularjs': ngNoRequireAngularJS,
|
|
34
|
+
'ng-no-require-module-deps': ngNoRequireModuleDeps,
|
|
35
|
+
'ng-strictdi': ngStrictDI,
|
|
36
|
+
'prefer-promise-like': preferPromiseLike,
|
|
37
|
+
'react2angular-with-error-boundary': react2angularWithErrorBoundary,
|
|
38
|
+
'rest-prefer-static-strings-in-initializer': restPreferStaticStringsInInitializer,
|
|
39
|
+
};
|
|
40
|
+
|
|
20
41
|
const plugin = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'api-no-unused-chaining': apiNoUnusedChaining,
|
|
29
|
-
'import-from-alias-not-npm': importFromAliasNotNpm,
|
|
30
|
-
'import-from-npm-not-alias': importFromNpmNotAlias,
|
|
31
|
-
'import-from-npm-not-relative': importFromNpmNotRelative,
|
|
32
|
-
'import-from-presentation-not-core': importFromPresentationNotCore,
|
|
33
|
-
'import-relative-within-subpackage': importRelativeWithinSubpackage,
|
|
34
|
-
'import-sort': importSort,
|
|
35
|
-
'migrate-to-mock-http-client': migrateToMockHttpClient,
|
|
36
|
-
'ng-no-component-class': ngNoComponentClass,
|
|
37
|
-
'ng-no-module-export': ngNoModuleExport,
|
|
38
|
-
'ng-no-require-angularjs': ngNoRequireAngularJS,
|
|
39
|
-
'ng-no-require-module-deps': ngNoRequireModuleDeps,
|
|
40
|
-
'ng-strictdi': ngStrictDI,
|
|
41
|
-
'prefer-promise-like': preferPromiseLike,
|
|
42
|
-
'react2angular-with-error-boundary': react2angularWithErrorBoundary,
|
|
43
|
-
'rest-prefer-static-strings-in-initializer': restPreferStaticStringsInInitializer,
|
|
42
|
+
rules,
|
|
43
|
+
// Configs are loaded lazily to avoid circular dependency
|
|
44
|
+
get configs() {
|
|
45
|
+
return {
|
|
46
|
+
base: require('./base.config.js'),
|
|
47
|
+
none: require('./none.config.js'),
|
|
48
|
+
};
|
|
44
49
|
},
|
|
45
50
|
};
|
|
46
51
|
|
package/none.config.js
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
const { globalIgnores } = require('eslint/config');
|
|
2
|
+
|
|
3
|
+
const tsParser = require('@typescript-eslint/parser');
|
|
4
|
+
const typescriptEslint = require('@typescript-eslint/eslint-plugin');
|
|
5
|
+
|
|
6
|
+
// Import rules directly to avoid circular dependency when this config is bundled in the plugin
|
|
7
|
+
// Use a function to get rules lazily
|
|
8
|
+
const getSpinnakerRules = () => require('./index.js').rules;
|
|
9
|
+
const globals = require('globals');
|
|
10
|
+
|
|
11
|
+
module.exports = [
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
parser: tsParser,
|
|
15
|
+
sourceType: 'module',
|
|
16
|
+
parserOptions: {},
|
|
17
|
+
|
|
18
|
+
globals: {
|
|
19
|
+
...globals.browser,
|
|
20
|
+
...globals.node,
|
|
21
|
+
...globals.jasmine,
|
|
22
|
+
angular: true,
|
|
23
|
+
$: true,
|
|
24
|
+
_: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
plugins: {
|
|
29
|
+
'@typescript-eslint': typescriptEslint,
|
|
30
|
+
'@spinnaker': { rules: getSpinnakerRules() },
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
rules: {},
|
|
12
34
|
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
$: true,
|
|
16
|
-
_: true,
|
|
17
|
-
},
|
|
18
|
-
};
|
|
35
|
+
globalIgnores(['**/*.spec.*', './template/**/*']),
|
|
36
|
+
];
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "git",
|
|
5
5
|
"url": "https://github.com/spinnaker/spinnaker.git"
|
|
6
6
|
},
|
|
7
|
-
"version": "2026.0
|
|
7
|
+
"version": "2026.1.0",
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"license": "Apache-2.0",
|
|
10
10
|
"publishConfig": {
|
|
@@ -23,25 +23,29 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@babel/preset-typescript": "^7.15.0",
|
|
26
|
-
"@
|
|
26
|
+
"@eslint/compat": "^2.0.2",
|
|
27
|
+
"@eslint/eslintrc": "^3.3.4",
|
|
28
|
+
"@eslint/js": "^9.39.2",
|
|
29
|
+
"@types/eslint": "9.6.1",
|
|
27
30
|
"@types/estree": "*",
|
|
28
|
-
"@types/jest": "^
|
|
31
|
+
"@types/jest": "^29.0.0",
|
|
29
32
|
"@types/lodash": "^4.14.165",
|
|
30
33
|
"@types/node": "^16.4.13",
|
|
31
|
-
"@typescript-eslint/parser": "
|
|
32
|
-
"@typescript-eslint/types": "
|
|
33
|
-
"eslint": "
|
|
34
|
+
"@typescript-eslint/parser": "8.54.0",
|
|
35
|
+
"@typescript-eslint/types": "8.54.0",
|
|
36
|
+
"eslint": "9.39.2",
|
|
34
37
|
"fast-glob": "^3.2.7",
|
|
35
|
-
"
|
|
38
|
+
"globals": "^17.2.0",
|
|
39
|
+
"jest": "^29.0.0",
|
|
36
40
|
"prettier": "*",
|
|
37
41
|
"typescript": "5.0.4"
|
|
38
42
|
},
|
|
39
43
|
"peerDependencies": {
|
|
40
|
-
"@typescript-eslint/eslint-plugin": "
|
|
41
|
-
"@typescript-eslint/parser": "
|
|
42
|
-
"eslint": "
|
|
43
|
-
"eslint-config-prettier": "
|
|
44
|
-
"eslint-plugin-react-hooks": "
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
45
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
46
|
+
"eslint": "^9.0.0",
|
|
47
|
+
"eslint-config-prettier": "^10.0.0",
|
|
48
|
+
"eslint-plugin-react-hooks": "^5.0.0 || ^7.0.0"
|
|
45
49
|
},
|
|
46
50
|
"peerDevDependencies": [
|
|
47
51
|
"@typescript-eslint/eslint-plugin",
|
|
@@ -54,7 +58,8 @@
|
|
|
54
58
|
"testPathIgnorePatterns": [
|
|
55
59
|
"<rootDir>/template",
|
|
56
60
|
"<rootDir>/rules/ng-strictdi.spec.ts"
|
|
57
|
-
]
|
|
61
|
+
],
|
|
62
|
+
"testEnvironment": "node"
|
|
58
63
|
},
|
|
59
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "b43289872672de89234911de45d1cba0dd18373f"
|
|
60
65
|
}
|
package/rules/api-deprecation.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type
|
|
2
|
+
import type * as ESTree from 'estree';
|
|
3
|
+
|
|
4
|
+
type CallExpression = ESTree.CallExpression;
|
|
5
|
+
type ImportDeclaration = ESTree.ImportDeclaration;
|
|
6
|
+
type ImportSpecifier = ESTree.ImportSpecifier;
|
|
7
|
+
type MemberExpression = ESTree.MemberExpression;
|
|
8
|
+
type Node = ESTree.Node;
|
|
3
9
|
import * as _ from 'lodash/fp';
|
|
4
10
|
|
|
5
11
|
import { getImportName } from '../utils/ast';
|
|
@@ -202,7 +208,8 @@ const rule: Rule.RuleModule = {
|
|
|
202
208
|
* - part of an xyz() call chained off a variable, e.g.: var foo = API.xyz(); foo.get()
|
|
203
209
|
* @param node {CallExpression}
|
|
204
210
|
*/
|
|
205
|
-
CallExpression(
|
|
211
|
+
CallExpression(_node: any) {
|
|
212
|
+
const node = _node as CallExpression & Rule.NodeParentExtension;
|
|
206
213
|
if (node.parent.type === 'MemberExpression' || !isAPICall(context, node)) {
|
|
207
214
|
return undefined;
|
|
208
215
|
}
|
package/rules/api-no-slashes.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type
|
|
2
|
+
import type * as ESTree from 'estree';
|
|
3
|
+
|
|
4
|
+
type CallExpression = ESTree.CallExpression;
|
|
5
|
+
type Identifier = ESTree.Identifier;
|
|
6
|
+
type Literal = ESTree.Literal;
|
|
3
7
|
import { get } from 'lodash';
|
|
4
8
|
|
|
5
9
|
import { getCallingIdentifier, getVariableInScope, isMemberExpression } from '../utils/utils';
|
|
@@ -12,7 +16,8 @@ import { getCallingIdentifier, getVariableInScope, isMemberExpression } from '..
|
|
|
12
16
|
*/
|
|
13
17
|
const rule = function (context: Rule.RuleContext) {
|
|
14
18
|
return {
|
|
15
|
-
CallExpression: function (
|
|
19
|
+
CallExpression: function (_node: any) {
|
|
20
|
+
const node = _node as CallExpression;
|
|
16
21
|
const callee = node.callee;
|
|
17
22
|
const args = node.arguments;
|
|
18
23
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { ImportDeclaration } from 'estree';
|
|
3
2
|
|
|
4
3
|
import { getImportFromNpm, getSourceFileDetails } from '../utils/import-aliases';
|
|
5
4
|
|
|
@@ -18,7 +17,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
return {
|
|
21
|
-
ImportDeclaration(
|
|
20
|
+
ImportDeclaration(_node: any) {
|
|
21
|
+
const node = _node;
|
|
22
22
|
if (node.source.type !== 'Literal' || !node.source.value) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { ImportDeclaration } from 'estree';
|
|
3
2
|
|
|
4
3
|
import { getAliasImport, getAllSpinnakerPackages, getSourceFileDetails } from '../utils/import-aliases';
|
|
5
4
|
|
|
@@ -21,7 +20,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
21
20
|
const allSpinnakerPackages = getAllSpinnakerPackages(modulesPath);
|
|
22
21
|
|
|
23
22
|
return {
|
|
24
|
-
ImportDeclaration: function (
|
|
23
|
+
ImportDeclaration: function (_node: any) {
|
|
24
|
+
const node = _node;
|
|
25
25
|
if (node.source.type !== 'Literal' || !node.source.value) {
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { ImportDeclaration } from 'estree';
|
|
3
2
|
|
|
4
3
|
import { getRelativeImport, getSourceFileDetails } from '../utils/import-aliases';
|
|
5
4
|
|
|
@@ -20,7 +19,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
return {
|
|
23
|
-
ImportDeclaration: function (
|
|
22
|
+
ImportDeclaration: function (_node: any) {
|
|
23
|
+
const node = _node;
|
|
24
24
|
if (node.source.type !== 'Literal' || !node.source.value) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { ImportDeclaration } from 'estree';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
|
|
5
4
|
import { getAliasImport, getAllSpinnakerPackages, getSourceFileDetails } from '../utils/import-aliases';
|
|
@@ -23,7 +22,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
23
22
|
const allSpinnakerPackages = getAllSpinnakerPackages(modulesPath);
|
|
24
23
|
|
|
25
24
|
return {
|
|
26
|
-
ImportDeclaration: function (
|
|
25
|
+
ImportDeclaration: function (_node: any) {
|
|
26
|
+
const node = _node;
|
|
27
27
|
if (node.source.type !== 'Literal' || !node.source.value) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { FunctionExpression, ImportDeclaration, ImportSpecifier } from 'estree';
|
|
3
2
|
|
|
4
3
|
import { getImportName } from '../utils/ast';
|
|
5
4
|
import { getProgram } from '../utils/utils';
|
|
@@ -9,13 +8,14 @@ const ruleModule: Rule.RuleModule = {
|
|
|
9
8
|
const text = (node) => context.getSourceCode().getText(node);
|
|
10
9
|
|
|
11
10
|
return {
|
|
12
|
-
CallExpression(
|
|
11
|
+
CallExpression(_node: any) {
|
|
12
|
+
const node = _node;
|
|
13
13
|
/** it(() => {}) */
|
|
14
14
|
const isItBlock = node.callee.type === 'Identifier' && node.callee.name === 'it';
|
|
15
15
|
|
|
16
16
|
if (isItBlock) {
|
|
17
17
|
const itBlockText = text(node);
|
|
18
|
-
const testFunction = node.arguments[1] as
|
|
18
|
+
const testFunction = node.arguments[1] as any;
|
|
19
19
|
|
|
20
20
|
const doesFunctionIncludeHttpBackend = !!testFunction && itBlockText.includes('$httpBackend');
|
|
21
21
|
|
|
@@ -38,12 +38,10 @@ const ruleModule: Rule.RuleModule = {
|
|
|
38
38
|
!text(testFunction.body.body[0]).includes('mockHttpClient')
|
|
39
39
|
) {
|
|
40
40
|
const program = getProgram(node);
|
|
41
|
-
const allImports = program.body.filter(
|
|
42
|
-
(item) => item.type === 'ImportDeclaration',
|
|
43
|
-
) as ImportDeclaration[];
|
|
41
|
+
const allImports = program.body.filter((item) => item.type === 'ImportDeclaration') as any[];
|
|
44
42
|
|
|
45
43
|
const importSpecifiers = allImports
|
|
46
|
-
.map((decl) => decl.specifiers as
|
|
44
|
+
.map((decl) => decl.specifiers as any[])
|
|
47
45
|
.reduce((acc, x) => acc.concat(x), []);
|
|
48
46
|
|
|
49
47
|
const mockHttpClientImport = importSpecifiers.find((specifier) => {
|
|
@@ -12,14 +12,13 @@ const findParentNodeByType = (node: Rule.Node, type: string) =>
|
|
|
12
12
|
* @category conventions
|
|
13
13
|
*/
|
|
14
14
|
import angularRule from '../utils/angular-rule/angular-rule';
|
|
15
|
-
import { isNewExpression } from '../utils/utils';
|
|
16
15
|
|
|
17
16
|
const useObjectLiteral = function (context: Rule.RuleContext) {
|
|
18
17
|
return {
|
|
19
18
|
'angular?component': function (callee, thisGuy) {
|
|
20
19
|
const node: Rule.Node = thisGuy.node;
|
|
21
20
|
const scope: Scope.Scope = thisGuy.scope;
|
|
22
|
-
if (
|
|
21
|
+
if (node.type === 'NewExpression') {
|
|
23
22
|
const calleeName = 'name' in node.callee ? node.callee.name : undefined;
|
|
24
23
|
const fix = (fixer: Rule.RuleFixer) => {
|
|
25
24
|
const variable = scope.variables.find((x) => x.name === calleeName);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { AST, Rule } from 'eslint';
|
|
6
|
-
import type { AssignmentExpression, CallExpression, MemberExpression } from 'estree';
|
|
7
6
|
import { isCallExpression, isIdentifier, isMemberExpression } from '../utils/utils';
|
|
8
7
|
|
|
9
8
|
const rule = function (context: Rule.RuleContext) {
|
|
@@ -20,7 +19,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
return {
|
|
23
|
-
AssignmentExpression: function (
|
|
22
|
+
AssignmentExpression: function (_node: any) {
|
|
23
|
+
const node = _node;
|
|
24
24
|
const left = node.left;
|
|
25
25
|
const right = node.right;
|
|
26
26
|
const isModuleExports = isModuleExportMemberExpression(left);
|
|
@@ -65,13 +65,13 @@ function getAngularModuleNameNode(node) {
|
|
|
65
65
|
if (!isCallExpression(node)) return false;
|
|
66
66
|
const callee = node.callee as Rule.Node;
|
|
67
67
|
|
|
68
|
-
function angularModuleNameNode(callExpression:
|
|
68
|
+
function angularModuleNameNode(callExpression: any) {
|
|
69
69
|
const isLiteral =
|
|
70
70
|
callExpression.arguments && callExpression.arguments[0] && callExpression.arguments[0].type === 'Literal';
|
|
71
71
|
return isLiteral ? callExpression.arguments[0] : undefined;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
function isChainedCallExpression(_callee:
|
|
74
|
+
function isChainedCallExpression(_callee: any): boolean {
|
|
75
75
|
if (isMemberExpression(_callee)) {
|
|
76
76
|
return _callee.object && _callee.object.type === 'CallExpression';
|
|
77
77
|
}
|
|
@@ -95,7 +95,7 @@ function getAngularModuleNameNode(node) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
if (isChainedCallExpression(callee)) {
|
|
98
|
-
return getAngularModuleNameNode(callee.object);
|
|
98
|
+
return getAngularModuleNameNode((callee as any).object);
|
|
99
99
|
} else if (isRawModuleCall(callee)) {
|
|
100
100
|
if (node.arguments && node.arguments[0] && node.arguments[0].type === 'Literal') return angularModuleNameNode(node);
|
|
101
101
|
} else if (isAngularModuleCall(callee)) {
|
|
@@ -8,19 +8,17 @@
|
|
|
8
8
|
* angular.module('mymodule', [])
|
|
9
9
|
*/
|
|
10
10
|
import type { Rule, Scope } from 'eslint';
|
|
11
|
-
import type { ImportDeclaration, MemberExpression } from 'estree';
|
|
12
11
|
import { getProgram, isMemberExpression } from '../utils/utils';
|
|
13
12
|
|
|
14
13
|
const rule = function (context: Rule.RuleContext) {
|
|
15
14
|
return {
|
|
16
|
-
'MemberExpression[object.name="angular"][property.name="module"]': function (
|
|
17
|
-
node
|
|
18
|
-
) {
|
|
15
|
+
'MemberExpression[object.name="angular"][property.name="module"]': function (_node: any) {
|
|
16
|
+
const node = _node;
|
|
19
17
|
const angularVar = findAngularVariable(node, context);
|
|
20
18
|
const angularImport = findAngularImportStatement(node);
|
|
21
19
|
// Double check that there is only a single use of 'angular' variable and that it's 'angular.module()')
|
|
22
20
|
if (angularImport && angularVar && angularVar.references.length === 1) {
|
|
23
|
-
const { parent } = angularVar.references[0].identifier as
|
|
21
|
+
const { parent } = angularVar.references[0].identifier as any;
|
|
24
22
|
if (isMemberExpression(parent)) {
|
|
25
23
|
if (
|
|
26
24
|
'name' in parent.object &&
|
|
@@ -46,7 +44,7 @@ function findAngularVariable(_node, context): Scope.Variable {
|
|
|
46
44
|
return moduleScope && moduleScope.variables.find((v) => v.name === 'angular');
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
function findAngularImportStatement(_node):
|
|
47
|
+
function findAngularImportStatement(_node): any {
|
|
50
48
|
let program = _node;
|
|
51
49
|
while (program && program.parent) {
|
|
52
50
|
program = program.parent;
|
|
@@ -59,7 +57,7 @@ function findAngularImportStatement(_node): ImportDeclaration {
|
|
|
59
57
|
node.source.type === 'Literal' &&
|
|
60
58
|
node.source.value === 'angular'
|
|
61
59
|
);
|
|
62
|
-
})
|
|
60
|
+
});
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
/*
|
|
@@ -71,7 +69,7 @@ import { module } from 'angular';
|
|
|
71
69
|
|
|
72
70
|
module('module', ['dep']);
|
|
73
71
|
*/
|
|
74
|
-
function getFixForAngularModule(angularDotModuleNode: Rule.Node, importStatement:
|
|
72
|
+
function getFixForAngularModule(angularDotModuleNode: Rule.Node, importStatement: any) {
|
|
75
73
|
return function (fixer: Rule.RuleFixer) {
|
|
76
74
|
return [
|
|
77
75
|
fixer.replaceText(angularDotModuleNode, 'module'),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { ArrayExpression, Node } from 'estree';
|
|
3
2
|
import fs from 'fs';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
|
|
@@ -12,7 +11,8 @@ import path from 'path';
|
|
|
12
11
|
*/
|
|
13
12
|
const rule = function (context: Rule.RuleContext) {
|
|
14
13
|
return {
|
|
15
|
-
ArrayExpression: function (
|
|
14
|
+
ArrayExpression: function (_node: any) {
|
|
15
|
+
const node = _node;
|
|
16
16
|
if (isInAngularModuleCall(node)) {
|
|
17
17
|
const requireDotNames = node.elements.map((element) => getRequireDotNameNode(element)).filter((x) => !!x);
|
|
18
18
|
requireDotNames.forEach(([_node, relativePath]) => {
|
|
@@ -54,7 +54,7 @@ angular.module('module', [
|
|
|
54
54
|
ANGULAR_UI_BOOTSTRAP
|
|
55
55
|
]);
|
|
56
56
|
*/
|
|
57
|
-
function getFixForBareRequire(node:
|
|
57
|
+
function getFixForBareRequire(node: any, requiredString: string) {
|
|
58
58
|
return function (fixer: Rule.RuleFixer) {
|
|
59
59
|
const variableName = requiredString.replace(/[^\w_]/g, '_').toUpperCase();
|
|
60
60
|
const lastImport = findLastImportStatement(node);
|
|
@@ -80,7 +80,7 @@ angular.module('module', [
|
|
|
80
80
|
SOME_REQUIRE_STRING
|
|
81
81
|
]);
|
|
82
82
|
*/
|
|
83
|
-
function getFixForRequireDotAnything(node:
|
|
83
|
+
function getFixForRequireDotAnything(node: any, requiredString: string, property: string) {
|
|
84
84
|
return function (fixer: Rule.RuleFixer) {
|
|
85
85
|
const variableName = requiredString
|
|
86
86
|
.replace(/^[^\w_]*/g, '')
|
|
@@ -109,7 +109,7 @@ angular.module('module', [
|
|
|
109
109
|
DEPENDENCY_SYMBOL
|
|
110
110
|
]);
|
|
111
111
|
*/
|
|
112
|
-
function getFixForRequireDotName(node:
|
|
112
|
+
function getFixForRequireDotName(node: any, filename: string, relativePath: string) {
|
|
113
113
|
const modulesPath = filename.replace(/modules\/.*/, 'modules/');
|
|
114
114
|
|
|
115
115
|
const path1 = path.resolve(filename, '..', relativePath);
|
|
@@ -138,7 +138,7 @@ function getFixForRequireDotName(node: Node, filename: string, relativePath: str
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
function findLastImportStatement(_node:
|
|
141
|
+
function findLastImportStatement(_node: any) {
|
|
142
142
|
let program = _node as Rule.Node;
|
|
143
143
|
while (program && program.parent) {
|
|
144
144
|
program = program.parent;
|
|
@@ -153,7 +153,7 @@ function findLastImportStatement(_node: Node) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// require('./some/nested/angularjs/module').name
|
|
156
|
-
function getRequireDotNameNode(node:
|
|
156
|
+
function getRequireDotNameNode(node: any): [any, string] {
|
|
157
157
|
if (node.type !== 'MemberExpression') return undefined;
|
|
158
158
|
if (node.property.type !== 'Identifier' || node.property.name !== 'name') return undefined;
|
|
159
159
|
if (node.object.type !== 'CallExpression' || (node.object.callee as any).name !== 'require') return undefined;
|
|
@@ -164,7 +164,7 @@ function getRequireDotNameNode(node: Node): [Node, string] {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
// require('something').anything
|
|
167
|
-
function getRequireDotAnythingNode(node:
|
|
167
|
+
function getRequireDotAnythingNode(node: any): [any, string, string] {
|
|
168
168
|
if (node.type !== 'MemberExpression') return undefined;
|
|
169
169
|
if (node.property.type !== 'Identifier') return undefined;
|
|
170
170
|
if (node.object.type !== 'CallExpression' || (node.object.callee as any).name !== 'require') return undefined;
|
|
@@ -175,7 +175,7 @@ function getRequireDotAnythingNode(node: Node): [Node, string, string] {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
// require('something')
|
|
178
|
-
function getBareRequireNode(node): [
|
|
178
|
+
function getBareRequireNode(node): [any, string] {
|
|
179
179
|
if (node.type !== 'CallExpression' || node.callee.name !== 'require') return undefined;
|
|
180
180
|
if (node.arguments.length !== 1 || node.arguments[0].type !== 'Literal') return undefined;
|
|
181
181
|
|
package/rules/ng-strictdi.ts
CHANGED
|
@@ -272,7 +272,7 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
272
272
|
'CallExpression:exit': function (node) {
|
|
273
273
|
const { object, property } = node.callee;
|
|
274
274
|
if (object && object.name === '$provide' && property && property.name === 'decorator') {
|
|
275
|
-
checkDi(null, { node: node.arguments[1], scope: context.getScope() });
|
|
275
|
+
checkDi(null, { node: node.arguments[1], scope: context.sourceCode.getScope(node) });
|
|
276
276
|
}
|
|
277
277
|
},
|
|
278
278
|
AssignmentExpression: function (node) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { TSESTree } from '@typescript-eslint/types';
|
|
2
2
|
import type { Rule } from 'eslint';
|
|
3
|
-
import type { ImportDeclaration } from 'estree';
|
|
4
3
|
import _ from 'lodash';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -50,7 +49,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
50
49
|
},
|
|
51
50
|
|
|
52
51
|
// If there are any unused IPromise imports, remove them
|
|
53
|
-
ImportDeclaration: function (
|
|
52
|
+
ImportDeclaration: function (_node: any) {
|
|
53
|
+
const node = _node;
|
|
54
54
|
const importIPromise = {
|
|
55
55
|
type: 'ImportSpecifier',
|
|
56
56
|
imported: {
|
|
@@ -66,7 +66,7 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
66
66
|
const specifiers = node.specifiers || [];
|
|
67
67
|
const foundIPromiseImport = specifiers.find((s) => _.isMatch(s, importIPromise));
|
|
68
68
|
|
|
69
|
-
const variables = context.getScope().variables;
|
|
69
|
+
const variables = context.sourceCode.getScope(node).variables;
|
|
70
70
|
const variable = variables.find((x) => x.defs.some((def) => def.node === foundIPromiseImport));
|
|
71
71
|
const unused = variable && variable.references.length === 0;
|
|
72
72
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import type { CallExpression, ImportDeclaration } from 'estree';
|
|
3
2
|
import _ from 'lodash';
|
|
4
3
|
import { isLiteral } from '../utils/utils';
|
|
5
4
|
|
|
@@ -9,12 +8,13 @@ import { isLiteral } from '../utils/utils';
|
|
|
9
8
|
* @version 0.1.0
|
|
10
9
|
*/
|
|
11
10
|
const rule = function (context: Rule.RuleContext) {
|
|
12
|
-
let coreImport:
|
|
11
|
+
let coreImport: any;
|
|
13
12
|
|
|
14
13
|
return {
|
|
15
14
|
// Find an import from @spinnaker/core or core/presentation
|
|
16
15
|
// This will be used to add the import for withErrorBoundary
|
|
17
|
-
ImportDeclaration: function (
|
|
16
|
+
ImportDeclaration: function (_node: any) {
|
|
17
|
+
const node = _node;
|
|
18
18
|
// import { foo, bar } from 'package';
|
|
19
19
|
// ^^^^^^^
|
|
20
20
|
const from = node.source.value || '';
|
|
@@ -22,7 +22,8 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
22
22
|
coreImport = node;
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
-
CallExpression: function (
|
|
25
|
+
CallExpression: function (_node: any) {
|
|
26
|
+
const node = _node;
|
|
26
27
|
// Find:
|
|
27
28
|
// react2angular(SomeComponent, ...)
|
|
28
29
|
const match = {
|
|
@@ -69,7 +70,7 @@ const rule = function (context: Rule.RuleContext) {
|
|
|
69
70
|
},
|
|
70
71
|
},
|
|
71
72
|
};
|
|
72
|
-
const isComponentCallExpression = (node): node is
|
|
73
|
+
const isComponentCallExpression = (node): node is any => _.isMatch(node, parentMatch);
|
|
73
74
|
|
|
74
75
|
let componentName = `'react2angular component'`;
|
|
75
76
|
const parentNode = node.parent;
|
|
@@ -24,11 +24,5 @@ ruleTester.run('rest-prefer-static-strings-in-initializer', rule, {
|
|
|
24
24
|
output: "REST('foo/bar').path('baz').get()",
|
|
25
25
|
errors: ["Prefer REST('/foo/bar') over REST().path('foo', 'bar')"],
|
|
26
26
|
},
|
|
27
|
-
{
|
|
28
|
-
// Process one path arg at a time
|
|
29
|
-
code: "REST('foo').path('bar', 'baz').get()",
|
|
30
|
-
output: "REST('foo/bar').path('baz').get()",
|
|
31
|
-
errors: ["Prefer REST('/foo/bar') over REST().path('foo', 'bar')"],
|
|
32
|
-
},
|
|
33
27
|
],
|
|
34
28
|
});
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { Rule } from 'eslint';
|
|
6
|
-
import type { CallExpression, Literal } from 'estree';
|
|
7
6
|
import * as _ from 'lodash/fp';
|
|
8
7
|
|
|
9
8
|
import { getCallChain, getCallingIdentifierName, isLiteral } from '../utils/utils';
|
|
@@ -15,7 +14,8 @@ const ruleModule: Rule.RuleModule = {
|
|
|
15
14
|
/**
|
|
16
15
|
* Look for chains of CallExpressions that are part of a REST().path() call
|
|
17
16
|
*/
|
|
18
|
-
CallExpression(
|
|
17
|
+
CallExpression(_node: any) {
|
|
18
|
+
const node = _node;
|
|
19
19
|
const callingIdentifierName = getCallingIdentifierName(node);
|
|
20
20
|
if (node.parent.type === 'MemberExpression' || callingIdentifierName !== 'REST') {
|
|
21
21
|
return undefined;
|
|
@@ -32,8 +32,8 @@ const ruleModule: Rule.RuleModule = {
|
|
|
32
32
|
const restCall = callChain[0];
|
|
33
33
|
const pathCall = callChain[1];
|
|
34
34
|
|
|
35
|
-
const restArg = restCall.arguments[0] as
|
|
36
|
-
const firstPathArg = pathCall.arguments[0] as
|
|
35
|
+
const restArg = restCall.arguments[0] as any;
|
|
36
|
+
const firstPathArg = pathCall.arguments[0] as any;
|
|
37
37
|
|
|
38
38
|
// Only REST('literal').path('literal', ...)
|
|
39
39
|
// Ignores: REST(variable) and REST().path(variable)
|
|
@@ -131,7 +131,7 @@ function angularRule(ruleDefinition) {
|
|
|
131
131
|
return {
|
|
132
132
|
callExpression: callExpressionNode,
|
|
133
133
|
node: findInjectedArgument(callExpressionNode),
|
|
134
|
-
scope: context.getScope(),
|
|
134
|
+
scope: context.sourceCode.getScope(callExpressionNode),
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -182,7 +182,7 @@ function angularRule(ruleDefinition) {
|
|
|
182
182
|
} else if (callee.object.type === 'Identifier') {
|
|
183
183
|
// var app = angular.module(); app.factory()
|
|
184
184
|
// ^^^^^^^
|
|
185
|
-
var scope = context.getScope();
|
|
185
|
+
var scope = context.sourceCode.getScope(callExpressionNode);
|
|
186
186
|
var isAngularModule = scope.variables.some(function (variable) {
|
|
187
187
|
if (callee.object.name !== variable.name) {
|
|
188
188
|
return false;
|
|
@@ -559,7 +559,8 @@ function isUIRouterStateDefinition(node) {
|
|
|
559
559
|
*/
|
|
560
560
|
function findIdentiferInScope(context, identifier) {
|
|
561
561
|
var identifierNode = null;
|
|
562
|
-
context.getScope().
|
|
562
|
+
var scope = context.sourceCode ? context.sourceCode.getScope(identifier) : context.getScope();
|
|
563
|
+
scope.variables.forEach(function (variable) {
|
|
563
564
|
if (variable.name === identifier.name) {
|
|
564
565
|
identifierNode = variable.defs[0].node;
|
|
565
566
|
if (identifierNode.type === 'VariableDeclarator') {
|
package/utils/ast.ts
CHANGED
package/utils/ruleTester.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const RuleTester = require('eslint').RuleTester;
|
|
2
2
|
module.exports = new RuleTester({
|
|
3
|
-
|
|
4
|
-
ecmaVersion:
|
|
3
|
+
languageOptions: {
|
|
4
|
+
ecmaVersion: 2017,
|
|
5
5
|
sourceType: 'module',
|
|
6
|
+
parser: require('@typescript-eslint/parser'),
|
|
6
7
|
},
|
|
7
|
-
parser: require.resolve('@typescript-eslint/parser'),
|
|
8
8
|
});
|
package/utils/utils.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import type { Rule, Scope } from 'eslint';
|
|
2
|
-
import type
|
|
3
|
-
CallExpression,
|
|
4
|
-
Expression,
|
|
5
|
-
Identifier,
|
|
6
|
-
Literal,
|
|
7
|
-
MemberExpression,
|
|
8
|
-
NewExpression,
|
|
9
|
-
Node,
|
|
10
|
-
Program,
|
|
11
|
-
SpreadElement,
|
|
12
|
-
} from 'estree';
|
|
2
|
+
import type * as ESTree from 'estree';
|
|
13
3
|
import * as _ from 'lodash/fp';
|
|
14
4
|
|
|
5
|
+
type Node = ESTree.Node;
|
|
6
|
+
type CallExpression = ESTree.CallExpression;
|
|
7
|
+
type Expression = ESTree.Expression;
|
|
8
|
+
type Identifier = ESTree.Identifier;
|
|
9
|
+
type Literal = ESTree.Literal;
|
|
10
|
+
type MemberExpression = ESTree.MemberExpression;
|
|
11
|
+
type NewExpression = ESTree.NewExpression;
|
|
12
|
+
type Program = ESTree.Program;
|
|
13
|
+
type SpreadElement = ESTree.SpreadElement;
|
|
14
|
+
|
|
15
15
|
export const getNodeType = (obj: Node) => obj?.type;
|
|
16
16
|
export const isType = <T extends Node>(type: string) => (obj: Node): obj is T => getNodeType(obj) === type;
|
|
17
17
|
export const isIdentifier = isType<Identifier>('Identifier');
|
|
@@ -53,7 +53,7 @@ export function getVariableInScope(context: Rule.RuleContext, identifier: Identi
|
|
|
53
53
|
return undefined;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const { references } = context.getScope();
|
|
56
|
+
const { references } = context.sourceCode.getScope((identifier as unknown) as Rule.Node);
|
|
57
57
|
const ref = references.find((r) => r.identifier.name === identifier.name);
|
|
58
58
|
return ref ? ref.resolved : undefined;
|
|
59
59
|
}
|
|
@@ -61,10 +61,10 @@ export function getVariableInScope(context: Rule.RuleContext, identifier: Identi
|
|
|
61
61
|
export const getVariableInitializer = _.get('defs[0].node.init');
|
|
62
62
|
|
|
63
63
|
export function getProgram(node: Node): Program {
|
|
64
|
-
let _node = node as
|
|
64
|
+
let _node = node as any;
|
|
65
65
|
while (_node.parent) {
|
|
66
66
|
if (_node.parent.type === 'Program') {
|
|
67
|
-
return _node.parent;
|
|
67
|
+
return _node.parent as Program;
|
|
68
68
|
}
|
|
69
69
|
_node = _node.parent;
|
|
70
70
|
}
|