@acdvs/eslint-plugin-amd 1.0.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/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/define-B8C8F-jq.cjs +118 -0
- package/dist/define-DldfQ_w6.mjs +89 -0
- package/dist/index.cjs +343 -0
- package/dist/index.d.cts +23 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +319 -0
- package/dist/types-OWk_tv7p.d.cts +475 -0
- package/dist/types-OWk_tv7p.d.mts +475 -0
- package/dist/utils/index.cjs +7 -0
- package/dist/utils/index.d.cts +20 -0
- package/dist/utils/index.d.mts +20 -0
- package/dist/utils/index.mjs +2 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, 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,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# eslint-plugin-amd
|
|
2
|
+
|
|
3
|
+
ESLint plugin for JavaScript AMD module syntax.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@acdvs/eslint-plugin-amd)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- Lints all AMD `define()` call shapes
|
|
11
|
+
- Detects dynamic `require()` calls
|
|
12
|
+
- Checks for mismatched dependency literals ↔ factory parameters
|
|
13
|
+
- Enforces path conventions (no extensions, sorted dependencies)
|
|
14
|
+
- Exports utility functions for use by other ESLint plugins
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm i -D eslint @acdvs/eslint-plugin-amd
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires ESLint 9+ flat config format.
|
|
23
|
+
|
|
24
|
+
## Configuration (ESLint 9+ flat config)
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
// eslint.config.js
|
|
28
|
+
import amd from '@acdvs/eslint-plugin-amd';
|
|
29
|
+
|
|
30
|
+
export default [
|
|
31
|
+
// Recommended rules
|
|
32
|
+
...amd.configs.recommended,
|
|
33
|
+
|
|
34
|
+
// Or configure rules individually
|
|
35
|
+
{
|
|
36
|
+
plugins: { amd },
|
|
37
|
+
rules: {
|
|
38
|
+
'amd/no-extra-deps': 'error',
|
|
39
|
+
'amd/no-extra-params': 'error',
|
|
40
|
+
'amd/no-invalid-define': 'error',
|
|
41
|
+
'amd/no-module-extensions': 'warn',
|
|
42
|
+
'amd/no-name': 'warn',
|
|
43
|
+
'amd/sorted-deps': ['warn', { order: 'asc' }],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rules
|
|
50
|
+
|
|
51
|
+
| Rule | Description | Recommended |
|
|
52
|
+
|:--|:--|:--:|
|
|
53
|
+
| [`amd/define-indicator`](docs/rules/define-indicator.md) | Enforce the presence of the AMD module `define()` indicator. | ❌ |
|
|
54
|
+
| [`amd/no-dynamic-require`](docs/rules/no-dynamic-require.md) | Disallow dynamic (non-literal) expressions in `require()` calls. | ❌ |
|
|
55
|
+
| [`amd/no-extra-deps`](docs/rules/no-extra-deps.md) | Disallow more dependency literals than factory parameters. | ✅ |
|
|
56
|
+
| [`amd/no-extra-params`](docs/rules/no-extra-params.md) | Disallow more factory parameters than dependency literals. | ✅ |
|
|
57
|
+
| [`amd/no-invalid-define`](docs/rules/no-invalid-define.md) | Disallow `define()` calls that do not match a valid AMD module signature. | ✅ |
|
|
58
|
+
| [`amd/no-module-extensions`](docs/rules/no-module-extensions.md) | Disallow file extensions in AMD dependency paths. | ✅ |
|
|
59
|
+
| [`amd/no-name`](docs/rules/no-name.md) | Disallow named AMD modules. | ✅ |
|
|
60
|
+
| [`amd/sorted-deps`](docs/rules/sorted-deps.md) | Enforce alphabetical ordering of `define()` dependency literals. | ❌ |
|
|
61
|
+
|
|
62
|
+
## Using utility functions in your own plugin
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
import amdUtils from '@acdvs/eslint-plugin-amd/utils';
|
|
66
|
+
|
|
67
|
+
create(context) {
|
|
68
|
+
return {
|
|
69
|
+
CallExpression(node) {
|
|
70
|
+
const defineCall = amdUtils.getDefineCall(node);
|
|
71
|
+
|
|
72
|
+
if (!defineCall) return;
|
|
73
|
+
|
|
74
|
+
// ...
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
//#region lib/utils/amd.ts
|
|
2
|
+
/**
|
|
3
|
+
* Determines if the source includes a `define.amd = { ... }` expression
|
|
4
|
+
* for indicating that any present `define` calls follow AMD spec.
|
|
5
|
+
* https://github.com/amdjs/amdjs-api/blob/master/AMD.md#defineamd-property-
|
|
6
|
+
*/
|
|
7
|
+
function hasAMDIndicator(sourceCode) {
|
|
8
|
+
return sourceCode.ast.body.some((stmt) => {
|
|
9
|
+
if (stmt.type !== "ExpressionStatement" || stmt.expression.type !== "AssignmentExpression") return false;
|
|
10
|
+
const { left, right } = stmt.expression;
|
|
11
|
+
return left.type === "MemberExpression" && !left.computed && left.object.type === "Identifier" && left.object.name === "define" && left.property.type === "Identifier" && left.property.name === "amd" && right.type === "ObjectExpression";
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region lib/utils/require.ts
|
|
16
|
+
function isRequireCall(node) {
|
|
17
|
+
return node.callee.type === "Identifier" && node.callee.name === "require";
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region lib/utils/define.ts
|
|
21
|
+
function isDefineCall(node) {
|
|
22
|
+
return node.callee.type === "Identifier" && node.callee.name === "define";
|
|
23
|
+
}
|
|
24
|
+
function isDefineName(node) {
|
|
25
|
+
return node.type === "Literal";
|
|
26
|
+
}
|
|
27
|
+
function isDefineDepArray(node) {
|
|
28
|
+
return node.type === "ArrayExpression" && node.elements.every((e) => e?.type === "Literal");
|
|
29
|
+
}
|
|
30
|
+
function isDefineFactory(node) {
|
|
31
|
+
return node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "ObjectExpression";
|
|
32
|
+
}
|
|
33
|
+
function factoryHasParams(node) {
|
|
34
|
+
return node.type !== "ObjectExpression" && node.params.length > 0;
|
|
35
|
+
}
|
|
36
|
+
function getDefineArgs(node) {
|
|
37
|
+
if (node.arguments.length === 0 || node.arguments.length > 3) return;
|
|
38
|
+
const args = node.arguments;
|
|
39
|
+
if (args.length === 1 && isDefineFactory(args[0])) return { factory: args[0] };
|
|
40
|
+
if (args.length === 2 && isDefineDepArray(args[0]) && isDefineFactory(args[1])) return {
|
|
41
|
+
dependencies: args[0],
|
|
42
|
+
factory: args[1]
|
|
43
|
+
};
|
|
44
|
+
if (args.length === 2 && isDefineName(args[0]) && isDefineFactory(args[1])) return {
|
|
45
|
+
name: args[0],
|
|
46
|
+
factory: args[1]
|
|
47
|
+
};
|
|
48
|
+
if (args.length === 3 && isDefineName(args[0]) && isDefineDepArray(args[1]) && isDefineFactory(args[2])) return {
|
|
49
|
+
name: args[0],
|
|
50
|
+
dependencies: args[1],
|
|
51
|
+
factory: args[2]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function getDependencyAnalysis(deps, factory) {
|
|
55
|
+
const depCount = deps?.elements.length || 0;
|
|
56
|
+
if (depCount === 0 && !factoryHasParams(factory)) return;
|
|
57
|
+
const maxLength = factory.type === "ObjectExpression" ? depCount : Math.max(depCount, factory.params.length);
|
|
58
|
+
const pairs = [];
|
|
59
|
+
const extraNames = [];
|
|
60
|
+
const extraParams = [];
|
|
61
|
+
for (let i = 0; i < maxLength; i++) {
|
|
62
|
+
const name = deps?.elements?.[i];
|
|
63
|
+
const param = factory.type === "ObjectExpression" ? void 0 : factory.params[i];
|
|
64
|
+
if (name && param) pairs.push({
|
|
65
|
+
name,
|
|
66
|
+
param
|
|
67
|
+
});
|
|
68
|
+
else if (name && !param) extraNames.push(name);
|
|
69
|
+
else if (!name && param) extraParams.push(param);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
pairs,
|
|
73
|
+
extraNames,
|
|
74
|
+
extraParams,
|
|
75
|
+
isBalanced: extraNames.length === 0 && extraParams.length === 0
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function getDefineCall(node) {
|
|
79
|
+
if (!isDefineCall(node)) return;
|
|
80
|
+
const args = getDefineArgs(node);
|
|
81
|
+
if (!args) return;
|
|
82
|
+
return {
|
|
83
|
+
args,
|
|
84
|
+
depAnalysis: getDependencyAnalysis(args.dependencies, args.factory),
|
|
85
|
+
node
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
Object.defineProperty(exports, "getDefineArgs", {
|
|
90
|
+
enumerable: true,
|
|
91
|
+
get: function() {
|
|
92
|
+
return getDefineArgs;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
Object.defineProperty(exports, "getDefineCall", {
|
|
96
|
+
enumerable: true,
|
|
97
|
+
get: function() {
|
|
98
|
+
return getDefineCall;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
Object.defineProperty(exports, "hasAMDIndicator", {
|
|
102
|
+
enumerable: true,
|
|
103
|
+
get: function() {
|
|
104
|
+
return hasAMDIndicator;
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
Object.defineProperty(exports, "isDefineCall", {
|
|
108
|
+
enumerable: true,
|
|
109
|
+
get: function() {
|
|
110
|
+
return isDefineCall;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
Object.defineProperty(exports, "isRequireCall", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
get: function() {
|
|
116
|
+
return isRequireCall;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//#region lib/utils/amd.ts
|
|
2
|
+
/**
|
|
3
|
+
* Determines if the source includes a `define.amd = { ... }` expression
|
|
4
|
+
* for indicating that any present `define` calls follow AMD spec.
|
|
5
|
+
* https://github.com/amdjs/amdjs-api/blob/master/AMD.md#defineamd-property-
|
|
6
|
+
*/
|
|
7
|
+
function hasAMDIndicator(sourceCode) {
|
|
8
|
+
return sourceCode.ast.body.some((stmt) => {
|
|
9
|
+
if (stmt.type !== "ExpressionStatement" || stmt.expression.type !== "AssignmentExpression") return false;
|
|
10
|
+
const { left, right } = stmt.expression;
|
|
11
|
+
return left.type === "MemberExpression" && !left.computed && left.object.type === "Identifier" && left.object.name === "define" && left.property.type === "Identifier" && left.property.name === "amd" && right.type === "ObjectExpression";
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region lib/utils/require.ts
|
|
16
|
+
function isRequireCall(node) {
|
|
17
|
+
return node.callee.type === "Identifier" && node.callee.name === "require";
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region lib/utils/define.ts
|
|
21
|
+
function isDefineCall(node) {
|
|
22
|
+
return node.callee.type === "Identifier" && node.callee.name === "define";
|
|
23
|
+
}
|
|
24
|
+
function isDefineName(node) {
|
|
25
|
+
return node.type === "Literal";
|
|
26
|
+
}
|
|
27
|
+
function isDefineDepArray(node) {
|
|
28
|
+
return node.type === "ArrayExpression" && node.elements.every((e) => e?.type === "Literal");
|
|
29
|
+
}
|
|
30
|
+
function isDefineFactory(node) {
|
|
31
|
+
return node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "ObjectExpression";
|
|
32
|
+
}
|
|
33
|
+
function factoryHasParams(node) {
|
|
34
|
+
return node.type !== "ObjectExpression" && node.params.length > 0;
|
|
35
|
+
}
|
|
36
|
+
function getDefineArgs(node) {
|
|
37
|
+
if (node.arguments.length === 0 || node.arguments.length > 3) return;
|
|
38
|
+
const args = node.arguments;
|
|
39
|
+
if (args.length === 1 && isDefineFactory(args[0])) return { factory: args[0] };
|
|
40
|
+
if (args.length === 2 && isDefineDepArray(args[0]) && isDefineFactory(args[1])) return {
|
|
41
|
+
dependencies: args[0],
|
|
42
|
+
factory: args[1]
|
|
43
|
+
};
|
|
44
|
+
if (args.length === 2 && isDefineName(args[0]) && isDefineFactory(args[1])) return {
|
|
45
|
+
name: args[0],
|
|
46
|
+
factory: args[1]
|
|
47
|
+
};
|
|
48
|
+
if (args.length === 3 && isDefineName(args[0]) && isDefineDepArray(args[1]) && isDefineFactory(args[2])) return {
|
|
49
|
+
name: args[0],
|
|
50
|
+
dependencies: args[1],
|
|
51
|
+
factory: args[2]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function getDependencyAnalysis(deps, factory) {
|
|
55
|
+
const depCount = deps?.elements.length || 0;
|
|
56
|
+
if (depCount === 0 && !factoryHasParams(factory)) return;
|
|
57
|
+
const maxLength = factory.type === "ObjectExpression" ? depCount : Math.max(depCount, factory.params.length);
|
|
58
|
+
const pairs = [];
|
|
59
|
+
const extraNames = [];
|
|
60
|
+
const extraParams = [];
|
|
61
|
+
for (let i = 0; i < maxLength; i++) {
|
|
62
|
+
const name = deps?.elements?.[i];
|
|
63
|
+
const param = factory.type === "ObjectExpression" ? void 0 : factory.params[i];
|
|
64
|
+
if (name && param) pairs.push({
|
|
65
|
+
name,
|
|
66
|
+
param
|
|
67
|
+
});
|
|
68
|
+
else if (name && !param) extraNames.push(name);
|
|
69
|
+
else if (!name && param) extraParams.push(param);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
pairs,
|
|
73
|
+
extraNames,
|
|
74
|
+
extraParams,
|
|
75
|
+
isBalanced: extraNames.length === 0 && extraParams.length === 0
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function getDefineCall(node) {
|
|
79
|
+
if (!isDefineCall(node)) return;
|
|
80
|
+
const args = getDefineArgs(node);
|
|
81
|
+
if (!args) return;
|
|
82
|
+
return {
|
|
83
|
+
args,
|
|
84
|
+
depAnalysis: getDependencyAnalysis(args.dependencies, args.factory),
|
|
85
|
+
node
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
export { hasAMDIndicator as a, isRequireCall as i, getDefineCall as n, isDefineCall as r, getDefineArgs as t };
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
const require_define = require("./define-B8C8F-jq.cjs");
|
|
24
|
+
let globals = require("globals");
|
|
25
|
+
globals = __toESM(globals, 1);
|
|
26
|
+
let node_path = require("node:path");
|
|
27
|
+
node_path = __toESM(node_path, 1);
|
|
28
|
+
//#region package.json
|
|
29
|
+
var name = "@acdvs/eslint-plugin-amd";
|
|
30
|
+
var version = "1.0.0";
|
|
31
|
+
var homepage = "https://github.com/acdvs/eslint-plugin-amd";
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region lib/rules/index.ts
|
|
34
|
+
var rules_default = {
|
|
35
|
+
"define-indicator": {
|
|
36
|
+
meta: {
|
|
37
|
+
type: "suggestion",
|
|
38
|
+
docs: {
|
|
39
|
+
description: "Enforce the presence of the AMD module `define()` indicator.",
|
|
40
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
41
|
+
},
|
|
42
|
+
fixable: "code",
|
|
43
|
+
schema: [],
|
|
44
|
+
messages: {
|
|
45
|
+
defineCallWithoutIndicator: "Missing AMD module `define` indicator: `define.amd = {}`",
|
|
46
|
+
indicatorWithoutDefineCall: "AMD module `define` indicator present without a `define()` call."
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
create: (context) => {
|
|
50
|
+
let hasDefineCall = false;
|
|
51
|
+
return {
|
|
52
|
+
"CallExpression[callee.name=define]": () => {
|
|
53
|
+
hasDefineCall = true;
|
|
54
|
+
},
|
|
55
|
+
"Program:exit": (program) => {
|
|
56
|
+
const hasIndicator = require_define.hasAMDIndicator(context.sourceCode);
|
|
57
|
+
if (hasDefineCall && !hasIndicator) {
|
|
58
|
+
context.report({
|
|
59
|
+
node: program,
|
|
60
|
+
messageId: "defineCallWithoutIndicator",
|
|
61
|
+
fix: (fixer) => {
|
|
62
|
+
return fixer.insertTextAfter(program, "\n\ndefine.amd = {};");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!hasDefineCall && hasIndicator) context.report({
|
|
68
|
+
node: program,
|
|
69
|
+
messageId: "indicatorWithoutDefineCall"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"no-dynamic-require": {
|
|
76
|
+
meta: {
|
|
77
|
+
type: "suggestion",
|
|
78
|
+
docs: {
|
|
79
|
+
description: "Disallow dynamic (non-literal) expressions in `require()` calls.",
|
|
80
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
81
|
+
},
|
|
82
|
+
schema: [],
|
|
83
|
+
messages: {
|
|
84
|
+
dynamicRequire: "`require()` argument must be a string literal or an array of string literals.",
|
|
85
|
+
dynamicRequireElement: "All elements of a `require()` dependency array must be string literals."
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
create: (context) => {
|
|
89
|
+
return { CallExpression: (node) => {
|
|
90
|
+
if (!require_define.isRequireCall(node) || node.arguments.length === 0) return;
|
|
91
|
+
const firstArg = node.arguments[0];
|
|
92
|
+
if (firstArg.type === "Literal") return;
|
|
93
|
+
if (firstArg.type === "ArrayExpression") {
|
|
94
|
+
for (const el of firstArg.elements) if (el === null || el.type !== "Literal") context.report({
|
|
95
|
+
node: el ?? firstArg,
|
|
96
|
+
messageId: "dynamicRequireElement"
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
context.report({
|
|
101
|
+
node: firstArg,
|
|
102
|
+
messageId: "dynamicRequire"
|
|
103
|
+
});
|
|
104
|
+
} };
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"no-extra-deps": {
|
|
108
|
+
meta: {
|
|
109
|
+
type: "suggestion",
|
|
110
|
+
docs: {
|
|
111
|
+
description: "Disallow more dependency literals than factory parameters.",
|
|
112
|
+
recommended: true,
|
|
113
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
114
|
+
},
|
|
115
|
+
schema: [{
|
|
116
|
+
type: "object",
|
|
117
|
+
properties: { ignoreValueFactory: {
|
|
118
|
+
type: "boolean",
|
|
119
|
+
default: true
|
|
120
|
+
} },
|
|
121
|
+
additionalProperties: false
|
|
122
|
+
}],
|
|
123
|
+
defaultOptions: [{ ignoreValueFactory: true }],
|
|
124
|
+
messages: { extraDep: "Dependency '{{dep}}' has no corresponding factory parameter. Add a parameter or remove the dependency." }
|
|
125
|
+
},
|
|
126
|
+
create: (context) => {
|
|
127
|
+
const { ignoreValueFactory } = context.options[0] ?? {};
|
|
128
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
129
|
+
const def = require_define.getDefineCall(node);
|
|
130
|
+
const hasValueFactory = def?.args.factory.type === "ObjectExpression";
|
|
131
|
+
if (!def?.depAnalysis || hasValueFactory && ignoreValueFactory) return;
|
|
132
|
+
for (const name of def.depAnalysis.extraNames) context.report({
|
|
133
|
+
node: name,
|
|
134
|
+
messageId: "extraDep",
|
|
135
|
+
data: { dep: String(name.value) }
|
|
136
|
+
});
|
|
137
|
+
} };
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"no-extra-params": {
|
|
141
|
+
meta: {
|
|
142
|
+
type: "problem",
|
|
143
|
+
docs: {
|
|
144
|
+
description: "Disallow more factory parameters than dependency literals.",
|
|
145
|
+
recommended: true,
|
|
146
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
147
|
+
},
|
|
148
|
+
schema: [],
|
|
149
|
+
messages: {
|
|
150
|
+
extraIdentParam: "Factory parameter '{{param}}' has no corresponding dependency literal. Add a dependency or remove the parameter.",
|
|
151
|
+
extraNonIdentParam: "Factory parameter has no corresponding dependency literal. Add a dependency or remove the parameter."
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
create: (context) => {
|
|
155
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
156
|
+
const def = require_define.getDefineCall(node);
|
|
157
|
+
if (!def?.depAnalysis) return;
|
|
158
|
+
for (const param of def.depAnalysis.extraParams) if (param.type === "Identifier") context.report({
|
|
159
|
+
node: param,
|
|
160
|
+
messageId: "extraIdentParam",
|
|
161
|
+
data: { param: param.name }
|
|
162
|
+
});
|
|
163
|
+
else context.report({
|
|
164
|
+
node: param,
|
|
165
|
+
messageId: "extraNonIdentParam"
|
|
166
|
+
});
|
|
167
|
+
} };
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"no-invalid-define": {
|
|
171
|
+
meta: {
|
|
172
|
+
type: "problem",
|
|
173
|
+
docs: {
|
|
174
|
+
description: "Disallow `define()` calls that do not match a valid AMD module signature.",
|
|
175
|
+
recommended: true,
|
|
176
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
177
|
+
},
|
|
178
|
+
schema: [],
|
|
179
|
+
messages: { invalidDefine: "`define()` call does not match a valid signature." }
|
|
180
|
+
},
|
|
181
|
+
create: (context) => {
|
|
182
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
183
|
+
if (!require_define.getDefineCall(node)) context.report({
|
|
184
|
+
node,
|
|
185
|
+
messageId: "invalidDefine"
|
|
186
|
+
});
|
|
187
|
+
} };
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"no-module-extensions": {
|
|
191
|
+
meta: {
|
|
192
|
+
type: "suggestion",
|
|
193
|
+
docs: {
|
|
194
|
+
description: "Disallow file extensions in AMD dependency paths.",
|
|
195
|
+
recommended: true,
|
|
196
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
197
|
+
},
|
|
198
|
+
schema: [{ oneOf: [{
|
|
199
|
+
type: "object",
|
|
200
|
+
properties: {
|
|
201
|
+
blacklist: {
|
|
202
|
+
type: "array",
|
|
203
|
+
items: { type: "string" },
|
|
204
|
+
minItems: 1,
|
|
205
|
+
uniqueItems: true,
|
|
206
|
+
description: "Extensions disallowed in dependency paths. If set, all other extensions are allowed."
|
|
207
|
+
},
|
|
208
|
+
whitelist: {
|
|
209
|
+
type: "array",
|
|
210
|
+
items: { type: "string" },
|
|
211
|
+
minItems: 1,
|
|
212
|
+
uniqueItems: true,
|
|
213
|
+
description: "Extensions allowed in dependency paths. If set, all other extensions are disallowed and any `blacklist` is ignored."
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
additionalProperties: false
|
|
217
|
+
}] }],
|
|
218
|
+
messages: {
|
|
219
|
+
blacklistedDefault: "Dependency '{{dep}}' should not include a file extension.",
|
|
220
|
+
blacklisted: "Dependency '{{dep}}' should not include a blacklisted file extension.",
|
|
221
|
+
notWhitelisted: "Dependency '{{dep}}' includes a non-whitelisted file extension."
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
create: (context) => {
|
|
225
|
+
const { blacklist, whitelist } = context.options[0] ?? {};
|
|
226
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
227
|
+
const def = require_define.getDefineCall(node);
|
|
228
|
+
if (!def?.args.dependencies) return;
|
|
229
|
+
for (const el of def.args.dependencies.elements) {
|
|
230
|
+
const literal = el;
|
|
231
|
+
const dep = literal.value;
|
|
232
|
+
if (!/(\.\w+)+$/.test(dep)) continue;
|
|
233
|
+
if (whitelist && whitelist.length > 0) {
|
|
234
|
+
if (!whitelist.some((ext) => dep.endsWith(ext))) context.report({
|
|
235
|
+
node: literal,
|
|
236
|
+
messageId: "notWhitelisted",
|
|
237
|
+
data: { dep }
|
|
238
|
+
});
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const isDefaultBlacklist = !blacklist;
|
|
242
|
+
if (isDefaultBlacklist || blacklist.some((ext) => dep.endsWith(ext))) context.report({
|
|
243
|
+
node: literal,
|
|
244
|
+
messageId: isDefaultBlacklist ? "blacklistedDefault" : "blacklisted",
|
|
245
|
+
data: { dep }
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
} };
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"no-name": {
|
|
252
|
+
meta: {
|
|
253
|
+
type: "suggestion",
|
|
254
|
+
docs: {
|
|
255
|
+
description: "Disallow named AMD modules.",
|
|
256
|
+
recommended: true,
|
|
257
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
258
|
+
},
|
|
259
|
+
schema: [],
|
|
260
|
+
messages: { noAmdName: "AMD module should be anonymous. Remove the name argument '{{name}}' from the `define()` call." }
|
|
261
|
+
},
|
|
262
|
+
create: (context) => {
|
|
263
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
264
|
+
const def = require_define.getDefineCall(node);
|
|
265
|
+
if (!def) return;
|
|
266
|
+
if (def.args.name) context.report({
|
|
267
|
+
node: def.args.name,
|
|
268
|
+
messageId: "noAmdName",
|
|
269
|
+
data: { name: def.args.name.value }
|
|
270
|
+
});
|
|
271
|
+
} };
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
"sorted-deps": {
|
|
275
|
+
meta: {
|
|
276
|
+
type: "suggestion",
|
|
277
|
+
docs: {
|
|
278
|
+
description: "Enforce alphabetical ordering of `define()` dependency literals.",
|
|
279
|
+
url: `${homepage}/blob/main/docs/rules/${node_path.default.basename(__filename, ".ts")}.md`
|
|
280
|
+
},
|
|
281
|
+
schema: [{
|
|
282
|
+
type: "object",
|
|
283
|
+
properties: { order: {
|
|
284
|
+
type: "string",
|
|
285
|
+
enum: ["asc", "desc"],
|
|
286
|
+
default: "asc"
|
|
287
|
+
} },
|
|
288
|
+
additionalProperties: false
|
|
289
|
+
}],
|
|
290
|
+
defaultOptions: [{ order: "asc" }],
|
|
291
|
+
messages: { wrongOrder: "Dependencies should be sorted in {{order}} order." }
|
|
292
|
+
},
|
|
293
|
+
create: (context) => {
|
|
294
|
+
const { order } = context.options[0] ?? {};
|
|
295
|
+
return { "CallExpression[callee.name=define]": (node) => {
|
|
296
|
+
const deps = require_define.getDefineCall(node)?.args.dependencies;
|
|
297
|
+
const els = deps?.elements;
|
|
298
|
+
if (!deps || !els) return;
|
|
299
|
+
for (let i = 1; i < els.length; i++) {
|
|
300
|
+
const prevEl = els[i - 1];
|
|
301
|
+
const currEl = els[i];
|
|
302
|
+
const prevDep = prevEl.value;
|
|
303
|
+
const currDep = currEl.value;
|
|
304
|
+
if (order === "asc" ? currDep < prevDep : currDep > prevDep) context.report({
|
|
305
|
+
node: deps,
|
|
306
|
+
messageId: "wrongOrder",
|
|
307
|
+
data: { order: order === "asc" ? "alphabetical" : `reverse alphabetical` }
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
} };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region lib/index.ts
|
|
316
|
+
const plugin = {
|
|
317
|
+
meta: {
|
|
318
|
+
name,
|
|
319
|
+
version
|
|
320
|
+
},
|
|
321
|
+
rules: rules_default,
|
|
322
|
+
configs: {}
|
|
323
|
+
};
|
|
324
|
+
const defaults = {
|
|
325
|
+
plugins: { amd: plugin },
|
|
326
|
+
languageOptions: {
|
|
327
|
+
sourceType: "commonjs",
|
|
328
|
+
globals: { ...globals.default.amd }
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
plugin.configs.all = [{
|
|
332
|
+
...defaults,
|
|
333
|
+
rules: Object.fromEntries(Object.entries(rules_default).map(entryToConfigArray))
|
|
334
|
+
}];
|
|
335
|
+
plugin.configs.recommended = [{
|
|
336
|
+
...defaults,
|
|
337
|
+
rules: Object.fromEntries(Object.entries(rules_default).filter(([, rule]) => rule.meta?.docs?.recommended).map(entryToConfigArray))
|
|
338
|
+
}];
|
|
339
|
+
function entryToConfigArray([name, rule]) {
|
|
340
|
+
return [`amd/${name}`, rule.meta?.type === "problem" ? "error" : "warn"];
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
module.exports = plugin;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { a as DependencyPair, i as DependencyAnalysis, n as DefineCall, r as DefineFactory, t as DefineArgs } from "./types-OWk_tv7p.cjs";
|
|
2
|
+
import { Linter, Rule } from "eslint";
|
|
3
|
+
|
|
4
|
+
//#region lib/index.d.ts
|
|
5
|
+
declare const plugin: {
|
|
6
|
+
meta: {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
};
|
|
10
|
+
rules: {
|
|
11
|
+
'define-indicator': Rule.RuleModule;
|
|
12
|
+
'no-dynamic-require': Rule.RuleModule;
|
|
13
|
+
'no-extra-deps': Rule.RuleModule;
|
|
14
|
+
'no-extra-params': Rule.RuleModule;
|
|
15
|
+
'no-invalid-define': Rule.RuleModule;
|
|
16
|
+
'no-module-extensions': Rule.RuleModule;
|
|
17
|
+
'no-name': Rule.RuleModule;
|
|
18
|
+
'sorted-deps': Rule.RuleModule;
|
|
19
|
+
};
|
|
20
|
+
configs: Record<string, Linter.Config[]>;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { DefineArgs, DefineCall, DefineFactory, DependencyAnalysis, DependencyPair, plugin as default };
|