eslint-plugin-node-dependencies 0.7.0 → 0.9.1

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 CHANGED
@@ -33,7 +33,7 @@ npm install --save-dev eslint eslint-plugin-node-dependencies
33
33
  > **Requirements**
34
34
  >
35
35
  > - ESLint v6.0.0 and above
36
- > - Node.js v12.x, v14.x and above
36
+ > - Node.js v14.16.0 and above
37
37
 
38
38
  <!--DOCS_IGNORE_END-->
39
39
 
@@ -119,6 +119,7 @@ The rules with the following star :star: are included in the `plugin:node-depend
119
119
  | Rule ID | Description | |
120
120
  |:--------|:------------|:---|
121
121
  | [node-dependencies/compat-engines](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/compat-engines.html) | enforce the versions of the engines of the dependencies to be compatible. | :star: |
122
+ | [node-dependencies/no-dupe-deps](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/no-dupe-deps.html) | disallow duplicate dependencies. | :star: |
122
123
  | [node-dependencies/valid-semver](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/valid-semver.html) | enforce versions that is valid as a semantic version. | :star: |
123
124
 
124
125
  ### Best Practices
@@ -127,6 +128,14 @@ The rules with the following star :star: are included in the `plugin:node-depend
127
128
  |:--------|:------------|:---|
128
129
  | [node-dependencies/absolute-version](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/absolute-version.html) | require or disallow absolute version of dependency. | |
129
130
  | [node-dependencies/no-deprecated](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/no-deprecated.html) | disallow having dependencies on deprecate packages. | |
131
+ | [node-dependencies/no-restricted-deps](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/no-restricted-deps.html) | Disallows dependence on the specified package. | |
132
+
133
+ ### Stylistic Issues
134
+
135
+ | Rule ID | Description | |
136
+ |:--------|:------------|:---|
137
+ | [node-dependencies/prefer-caret-range-version](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/prefer-caret-range-version.html) | require caret(`^`) version instead of range version. | :wrench: |
138
+ | [node-dependencies/prefer-tilde-range-version](https://ota-meshi.github.io/eslint-plugin-node-dependencies/rules/prefer-tilde-range-version.html) | require tilde(`~`) version instead of range version. | :wrench: |
130
139
 
131
140
  ### Deprecated
132
141
 
@@ -7,6 +7,7 @@ module.exports = {
7
7
  parser: require.resolve("jsonc-eslint-parser"),
8
8
  rules: {
9
9
  "node-dependencies/compat-engines": "error",
10
+ "node-dependencies/no-dupe-deps": "error",
10
11
  "node-dependencies/valid-semver": "error",
11
12
  },
12
13
  },
@@ -100,6 +100,9 @@ exports.default = (0, utils_1.createRule)("absolute-version", {
100
100
  type: "suggestion",
101
101
  },
102
102
  create(context) {
103
+ if (!context.parserServices.isJSON) {
104
+ return {};
105
+ }
103
106
  const getOption = parseOption(context.options[0]);
104
107
  function defineVisitor(visitName) {
105
108
  return (node) => {
@@ -160,7 +160,7 @@ exports.default = (0, utils_1.createRule)("compat-engines", {
160
160
  }
161
161
  function processDependencyModule(ctx, name, ver, modules, node) {
162
162
  const currModules = [...modules, `${name}@${ver}`];
163
- processMeta(ctx, (0, meta_1.getMetaFromNodeModules)(name, ver, context));
163
+ processMeta(ctx, (0, meta_1.getMetaFromNodeModules)(name, ver, { context }));
164
164
  if (!ctx.hasInvalid() && ctx.isAllProcessed()) {
165
165
  return;
166
166
  }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("../utils");
4
+ const ast_utils_1 = require("../utils/ast-utils");
5
+ const DEPS = [
6
+ "dependencies",
7
+ "peerDependencies",
8
+ "optionalDependencies",
9
+ "devDependencies",
10
+ ];
11
+ class AllowDuplicates {
12
+ constructor() {
13
+ this.edges = [];
14
+ }
15
+ add(d1, d2) {
16
+ this.edges.push([d1, d2]);
17
+ }
18
+ isAllowedDuplicate(dep1, dep2) {
19
+ return this.edges.some(([d1, d2]) => (d1 === dep1 && d2 === dep2) || (d2 === dep1 && d1 === dep2));
20
+ }
21
+ }
22
+ exports.default = (0, utils_1.createRule)("no-dupe-deps", {
23
+ meta: {
24
+ docs: {
25
+ description: "disallow duplicate dependencies.",
26
+ category: "Possible Errors",
27
+ recommended: true,
28
+ },
29
+ schema: [],
30
+ messages: {
31
+ duplicated: "Duplicated dependency '{{name}}'.",
32
+ },
33
+ type: "problem",
34
+ },
35
+ create(context) {
36
+ if (!context.parserServices.isJSON) {
37
+ return {};
38
+ }
39
+ const allowDuplicates = new AllowDuplicates();
40
+ allowDuplicates.add("devDependencies", "peerDependencies");
41
+ allowDuplicates.add("devDependencies", "optionalDependencies");
42
+ const maps = {
43
+ dependencies: new Map(),
44
+ peerDependencies: new Map(),
45
+ optionalDependencies: new Map(),
46
+ devDependencies: new Map(),
47
+ };
48
+ const reported = new Set();
49
+ function report(name, node) {
50
+ if (reported.has(node)) {
51
+ return;
52
+ }
53
+ reported.add(node);
54
+ context.report({
55
+ loc: node.key.loc,
56
+ messageId: "duplicated",
57
+ data: {
58
+ name,
59
+ },
60
+ });
61
+ }
62
+ function verify(depsName, name, node) {
63
+ for (const dep of DEPS) {
64
+ if (allowDuplicates.isAllowedDuplicate(dep, depsName)) {
65
+ continue;
66
+ }
67
+ const dupeNode = maps[dep].get(name);
68
+ if (dupeNode) {
69
+ report(name, dupeNode);
70
+ report(name, node);
71
+ }
72
+ }
73
+ }
74
+ function defineVisitor(depsName) {
75
+ return (node) => {
76
+ const name = String((0, ast_utils_1.getKeyFromJSONProperty)(node));
77
+ verify(depsName, name, node);
78
+ maps[depsName].set(name, node);
79
+ };
80
+ }
81
+ return (0, utils_1.defineJsonVisitor)({
82
+ dependencies: defineVisitor("dependencies"),
83
+ peerDependencies: defineVisitor("peerDependencies"),
84
+ optionalDependencies: defineVisitor("optionalDependencies"),
85
+ devDependencies: defineVisitor("devDependencies"),
86
+ });
87
+ },
88
+ });
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("../utils");
4
+ const regexp_1 = require("../utils/regexp");
5
+ const semver_1 = require("semver");
6
+ const semver_2 = require("../utils/semver");
7
+ const ast_utils_1 = require("../utils/ast-utils");
8
+ const jsonc_eslint_parser_1 = require("jsonc-eslint-parser");
9
+ const meta_1 = require("../utils/meta");
10
+ const DEPS = [
11
+ "dependencies",
12
+ "peerDependencies",
13
+ "optionalDependencies",
14
+ ];
15
+ class Deps {
16
+ constructor() {
17
+ this.map = Object.create(null);
18
+ this.list = [];
19
+ }
20
+ push(name, ver, ownerPackageJsonPath) {
21
+ const range = (0, semver_2.getSemverRange)(ver);
22
+ if (range) {
23
+ const data = this.map[name];
24
+ if (data) {
25
+ const newRange = (0, semver_2.normalizeSemverRange)(data.range, range);
26
+ this.map[name] = {
27
+ range: newRange,
28
+ ownerPackageJsonPath: ownerPackageJsonPath || data.ownerPackageJsonPath,
29
+ };
30
+ }
31
+ else {
32
+ this.map[name] = {
33
+ range,
34
+ ownerPackageJsonPath,
35
+ };
36
+ }
37
+ return;
38
+ }
39
+ this.list.push({ name, ver, ownerPackageJsonPath });
40
+ }
41
+ pop() {
42
+ const resultForList = this.list.shift();
43
+ if (resultForList) {
44
+ return resultForList;
45
+ }
46
+ const [key] = Object.keys(this.map);
47
+ if (key) {
48
+ const data = this.map[key];
49
+ delete this.map[key];
50
+ return {
51
+ name: key,
52
+ ver: (0, semver_2.normalizeVer)(data.range),
53
+ ownerPackageJsonPath: data.ownerPackageJsonPath,
54
+ };
55
+ }
56
+ return null;
57
+ }
58
+ }
59
+ class DeepValidateContext {
60
+ constructor(context, validator) {
61
+ this.deepValidatedCache = new Map();
62
+ this.context = context;
63
+ this.validator = validator;
64
+ }
65
+ buildDeepValidator(deepOption) {
66
+ return (n, v) => this.deepDepsValidate(n, v, deepOption);
67
+ }
68
+ deepDepsValidate(packageName, version, deepOption) {
69
+ const { validator: validate, context } = this;
70
+ const depsQueue = new Deps();
71
+ depsQueue.push(packageName, version);
72
+ let dep;
73
+ while ((dep = depsQueue.pop())) {
74
+ const key = `${dep.name}@${dep.ver}`;
75
+ if (this.deepValidatedCache.has(key)) {
76
+ const result = this.deepValidatedCache.get(key);
77
+ if (result) {
78
+ return result;
79
+ }
80
+ }
81
+ else {
82
+ const result = validateWithoutCache(dep.name, dep.ver, dep.ownerPackageJsonPath);
83
+ this.deepValidatedCache.set(key, result);
84
+ if (result) {
85
+ return result;
86
+ }
87
+ }
88
+ }
89
+ return null;
90
+ function validateWithoutCache(name, ver, ownerPackageJsonPath) {
91
+ const result = validate(name, ver);
92
+ if (result) {
93
+ return result;
94
+ }
95
+ for (const { name: n, ver: v, packageJsonPath } of iterateDeps(name, ver, ownerPackageJsonPath)) {
96
+ const r = validate(n, v);
97
+ if (r) {
98
+ return r;
99
+ }
100
+ depsQueue.push(n, v, packageJsonPath);
101
+ }
102
+ return null;
103
+ }
104
+ function* iterateDeps(name, ver, ownerPackageJsonPath) {
105
+ yield* iterateDepsForMeta((0, meta_1.getMetaFromNodeModules)(name, ver, {
106
+ context,
107
+ ownerPackageJsonPath,
108
+ }));
109
+ if (deepOption === "server") {
110
+ const metaData = (0, meta_1.getMetaFromNpm)(name, ver);
111
+ for (const meta of metaData.cache) {
112
+ yield* iterateDepsForMeta(meta);
113
+ }
114
+ const metaList = metaData.get();
115
+ if (metaList) {
116
+ for (const meta of metaList) {
117
+ yield* iterateDepsForMeta(meta);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ function* iterateDepsForMeta(meta) {
123
+ if (!meta) {
124
+ return;
125
+ }
126
+ for (const depName of DEPS) {
127
+ const deps = meta[depName];
128
+ if (!deps) {
129
+ continue;
130
+ }
131
+ for (const [n, v] of Object.entries(deps)) {
132
+ if (typeof v === "string") {
133
+ yield { name: n, ver: v, packageJsonPath: meta._where };
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ exports.default = (0, utils_1.createRule)("no-restricted-deps", {
141
+ meta: {
142
+ docs: {
143
+ description: "Disallows dependence on the specified package.",
144
+ category: "Best Practices",
145
+ recommended: false,
146
+ },
147
+ schema: {
148
+ type: "array",
149
+ items: {
150
+ oneOf: [
151
+ {
152
+ type: "string",
153
+ },
154
+ {
155
+ type: "object",
156
+ properties: {
157
+ package: { type: "string" },
158
+ version: { type: "string" },
159
+ message: { type: "string" },
160
+ deep: { enum: ["local", "server"] },
161
+ },
162
+ required: ["package"],
163
+ additionalProperties: false,
164
+ },
165
+ ],
166
+ },
167
+ uniqueItems: true,
168
+ minItems: 0,
169
+ },
170
+ messages: {
171
+ restricted: "{{message}}",
172
+ },
173
+ type: "suggestion",
174
+ },
175
+ create(context) {
176
+ if (!context.parserServices.isJSON) {
177
+ return {};
178
+ }
179
+ const validateForPackage = parseOptions(context.options);
180
+ function defineVisitor(_depsName) {
181
+ return (node) => {
182
+ const name = String((0, ast_utils_1.getKeyFromJSONProperty)(node));
183
+ const ver = String((0, jsonc_eslint_parser_1.getStaticJSONValue)(node.value));
184
+ const result = validateForPackage(name, ver);
185
+ if (!result) {
186
+ return;
187
+ }
188
+ context.report({
189
+ loc: node.loc,
190
+ messageId: "restricted",
191
+ data: result,
192
+ });
193
+ };
194
+ }
195
+ return (0, utils_1.defineJsonVisitor)({
196
+ dependencies: defineVisitor("dependencies"),
197
+ peerDependencies: defineVisitor("peerDependencies"),
198
+ optionalDependencies: defineVisitor("optionalDependencies"),
199
+ devDependencies: defineVisitor("devDependencies"),
200
+ });
201
+ function matchVersions(version, optionVersion) {
202
+ if (!optionVersion) {
203
+ return true;
204
+ }
205
+ const range = (0, semver_2.getSemverRange)(version);
206
+ return Boolean(range && (0, semver_1.intersects)(range, optionVersion));
207
+ }
208
+ function parseOption(option) {
209
+ if (typeof option === "string") {
210
+ const regexp = (0, regexp_1.toRegExp)(option);
211
+ return (n, _v) => {
212
+ if (regexp.test(n)) {
213
+ return {
214
+ message: `Depend on '${option}' is not allowed.`,
215
+ };
216
+ }
217
+ return null;
218
+ };
219
+ }
220
+ const regexp = (0, regexp_1.toRegExp)(option.package);
221
+ const version = option.version
222
+ ? (0, semver_2.getSemverRange)(option.version)
223
+ : null;
224
+ const validator = (n, v) => {
225
+ if (regexp.test(n) && matchVersions(v, version)) {
226
+ return {
227
+ message: option.message || buildDefaultMessage(option),
228
+ };
229
+ }
230
+ return null;
231
+ };
232
+ if (!option.deep) {
233
+ return validator;
234
+ }
235
+ const deepValidateContext = new DeepValidateContext(context, validator);
236
+ return deepValidateContext.buildDeepValidator(option.deep);
237
+ function buildDefaultMessage(objectOption) {
238
+ const versionForMessage = objectOption.version
239
+ ? `@${objectOption.version}`
240
+ : "";
241
+ if (objectOption.package.startsWith("/") && versionForMessage) {
242
+ return `Depend on '${objectOption.package} ${versionForMessage}' is not allowed.`;
243
+ }
244
+ return `Depend on '${objectOption.package}${versionForMessage}' is not allowed.`;
245
+ }
246
+ }
247
+ function parseOptions(options) {
248
+ const validators = options.map(parseOption);
249
+ return (packageName, version) => {
250
+ for (const validator of validators) {
251
+ const result = validator(packageName, version);
252
+ if (result)
253
+ return result;
254
+ }
255
+ return null;
256
+ };
257
+ }
258
+ },
259
+ });
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const semver_1 = require("semver");
4
+ const utils_1 = require("../utils");
5
+ const semver_2 = require("../utils/semver");
6
+ const semver_range_1 = require("../utils/semver-range");
7
+ exports.default = (0, utils_1.createRule)("prefer-caret-range-version", {
8
+ meta: {
9
+ docs: {
10
+ description: "require caret(`^`) version instead of range version.",
11
+ category: "Stylistic Issues",
12
+ recommended: false,
13
+ },
14
+ fixable: "code",
15
+ schema: [],
16
+ messages: {},
17
+ type: "suggestion",
18
+ },
19
+ create(context) {
20
+ if (!context.parserServices.isJSON) {
21
+ return {};
22
+ }
23
+ const sourceCode = context.getSourceCode();
24
+ function convertToUseCaret(range) {
25
+ if (range.comparators.length !== 2) {
26
+ return null;
27
+ }
28
+ const start = range.comparators.find((c) => c.operator === ">=");
29
+ const end = range.comparators.find((c) => c.operator === "<");
30
+ if (!start || !end) {
31
+ return null;
32
+ }
33
+ const caretRangeText = `^${start.semver.version}`;
34
+ const caretRange = (0, semver_2.getSemverRange)(caretRangeText);
35
+ if (!caretRange) {
36
+ return null;
37
+ }
38
+ const caretEnd = caretRange.set[0].find((c) => c.operator === "<");
39
+ if (!caretEnd) {
40
+ return null;
41
+ }
42
+ if (caretEnd.semver.compare(end.semver) !== 0) {
43
+ const endPre = new semver_1.SemVer(`${end.semver.version}-0`);
44
+ if (caretEnd.semver.compare(endPre) !== 0) {
45
+ return null;
46
+ }
47
+ }
48
+ return caretRangeText;
49
+ }
50
+ function verifyRange(range, node) {
51
+ const fixedRange = convertToUseCaret(range);
52
+ if (!fixedRange) {
53
+ return;
54
+ }
55
+ context.report({
56
+ loc: {
57
+ start: sourceCode.getLocFromIndex(node.range[0] + range.range[0]),
58
+ end: sourceCode.getLocFromIndex(node.range[0] + range.range[1]),
59
+ },
60
+ message: `Use '${fixedRange}' syntax instead.`,
61
+ fix(fixer) {
62
+ return fixer.replaceTextRange(node.range, JSON.stringify(node.value.slice(0, range.range[0]) +
63
+ fixedRange +
64
+ node.value.slice(range.range[1])));
65
+ },
66
+ });
67
+ }
68
+ function verifyVersion(node) {
69
+ if (maybeDepId(node.value)) {
70
+ return;
71
+ }
72
+ for (const range of (0, semver_range_1.iterateSemverRanges)(node.value)) {
73
+ const lowerRange = range.value.toLowerCase();
74
+ if (!lowerRange.startsWith("~")) {
75
+ if (lowerRange.startsWith("^") ||
76
+ /^\d+$/u.test(range.value) ||
77
+ ((range.value.endsWith(".x") ||
78
+ range.value.endsWith(".*")) &&
79
+ !/\s+-\s+/u.test(range.value)))
80
+ continue;
81
+ }
82
+ verifyRange(range, node);
83
+ }
84
+ }
85
+ return (0, utils_1.defineJsonVisitor)({
86
+ "engines, dependencies, peerDependencies, devDependencies, optionalDependencies"(node) {
87
+ if (isJSONStringLiteral(node.value)) {
88
+ verifyVersion(node.value);
89
+ }
90
+ },
91
+ });
92
+ },
93
+ });
94
+ function isJSONStringLiteral(node) {
95
+ return node.type === "JSONLiteral" && typeof node.value === "string";
96
+ }
97
+ function maybeDepId(ver) {
98
+ return ver.includes("/") || ver.includes(":") || /^[-a-z]+$/.test(ver);
99
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const semver_1 = require("semver");
4
+ const utils_1 = require("../utils");
5
+ const semver_2 = require("../utils/semver");
6
+ const semver_range_1 = require("../utils/semver-range");
7
+ exports.default = (0, utils_1.createRule)("prefer-tilde-range-version", {
8
+ meta: {
9
+ docs: {
10
+ description: "require tilde(`~`) version instead of range version.",
11
+ category: "Stylistic Issues",
12
+ recommended: false,
13
+ },
14
+ fixable: "code",
15
+ schema: [],
16
+ messages: {},
17
+ type: "suggestion",
18
+ },
19
+ create(context) {
20
+ if (!context.parserServices.isJSON) {
21
+ return {};
22
+ }
23
+ const sourceCode = context.getSourceCode();
24
+ function convertToUseTilde(range) {
25
+ if (range.comparators.length !== 2) {
26
+ return null;
27
+ }
28
+ const start = range.comparators.find((c) => c.operator === ">=");
29
+ const end = range.comparators.find((c) => c.operator === "<");
30
+ if (!start || !end) {
31
+ return null;
32
+ }
33
+ const tildeRangeText = `~${start.semver.version}`;
34
+ const tildeRange = (0, semver_2.getSemverRange)(tildeRangeText);
35
+ if (!tildeRange) {
36
+ return null;
37
+ }
38
+ const tildeEnd = tildeRange.set[0].find((c) => c.operator === "<");
39
+ if (!tildeEnd) {
40
+ return null;
41
+ }
42
+ if (tildeEnd.semver.compare(end.semver) !== 0) {
43
+ const endPre = new semver_1.SemVer(`${end.semver.version}-0`);
44
+ if (tildeEnd.semver.compare(endPre) !== 0) {
45
+ return null;
46
+ }
47
+ }
48
+ return tildeRangeText;
49
+ }
50
+ function verifyRange(range, node) {
51
+ const fixedRange = convertToUseTilde(range);
52
+ if (!fixedRange) {
53
+ return;
54
+ }
55
+ context.report({
56
+ loc: {
57
+ start: sourceCode.getLocFromIndex(node.range[0] + range.range[0]),
58
+ end: sourceCode.getLocFromIndex(node.range[0] + range.range[1]),
59
+ },
60
+ message: `Use '${fixedRange}' syntax instead.`,
61
+ fix(fixer) {
62
+ return fixer.replaceTextRange(node.range, JSON.stringify(node.value.slice(0, range.range[0]) +
63
+ fixedRange +
64
+ node.value.slice(range.range[1])));
65
+ },
66
+ });
67
+ }
68
+ function verifyVersion(node) {
69
+ if (maybeDepId(node.value)) {
70
+ return;
71
+ }
72
+ for (const range of (0, semver_range_1.iterateSemverRanges)(node.value)) {
73
+ const lowerRange = range.value.toLowerCase();
74
+ if (!lowerRange.startsWith("^")) {
75
+ if (lowerRange.startsWith("~") ||
76
+ /^\d+$/u.test(range.value) ||
77
+ /^\d+\.\d+$/u.test(range.value) ||
78
+ ((range.value.endsWith(".x") ||
79
+ range.value.endsWith(".*")) &&
80
+ !/\s+-\s+/u.test(range.value)))
81
+ continue;
82
+ }
83
+ verifyRange(range, node);
84
+ }
85
+ }
86
+ return (0, utils_1.defineJsonVisitor)({
87
+ "engines, dependencies, peerDependencies, devDependencies, optionalDependencies"(node) {
88
+ if (isJSONStringLiteral(node.value)) {
89
+ verifyVersion(node.value);
90
+ }
91
+ },
92
+ });
93
+ },
94
+ });
95
+ function isJSONStringLiteral(node) {
96
+ return node.type === "JSONLiteral" && typeof node.value === "string";
97
+ }
98
+ function maybeDepId(ver) {
99
+ return ver.includes("/") || ver.includes(":") || /^[-a-z]+$/.test(ver);
100
+ }
@@ -36,7 +36,7 @@ exports.default = (0, utils_1.createRule)("valid-semver", {
36
36
  });
37
37
  }
38
38
  },
39
- "dependencies, peerDependencies, devDependencies"(node) {
39
+ "dependencies, peerDependencies, devDependencies, optionalDependencies"(node) {
40
40
  const name = (0, ast_utils_1.getKeyFromJSONProperty)(node);
41
41
  if (typeof name !== "string") {
42
42
  return;
@@ -1,36 +1,55 @@
1
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 (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.getDependencies = exports.getEngines = exports.getMetaFromNpm = exports.getMetaFromNodeModules = void 0;
7
30
  const module_1 = __importDefault(require("module"));
8
- const child_process_1 = require("child_process");
9
- const path_1 = __importDefault(require("path"));
31
+ const path_1 = __importStar(require("path"));
10
32
  const fs_1 = __importDefault(require("fs"));
11
33
  const semver_1 = require("./semver");
12
34
  const semver_2 = require("semver");
13
35
  const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
36
+ const package_json_1 = require("./package-json");
14
37
  const TTL = 1000 * 60 * 60;
15
- const NPM_INFO_PROPERTIES = [
16
- "version",
17
- "engines",
18
- "deprecated",
19
- "dependencies",
20
- "peerDependencies",
21
- "dist-tags",
22
- ];
23
38
  const CACHED_META_ROOT = path_1.default.join(__dirname, `../../.cached_meta`);
24
- function getMetaFromNodeModules(name, ver, context) {
39
+ function getMetaFromNodeModules(name, ver, options) {
25
40
  try {
26
- const cwd = getCwd(context);
27
- const relativeTo = path_1.default.join(cwd, "__placeholder__.js");
41
+ const ownerJsonPath = options.ownerPackageJsonPath || options.context.getFilename();
42
+ const relativeTo = path_1.default.join(ownerJsonPath && path_1.default.isAbsolute(ownerJsonPath)
43
+ ? (0, path_1.dirname)(ownerJsonPath)
44
+ : getCwd(options.context), "__placeholder__.js");
28
45
  const req = module_1.default.createRequire(relativeTo);
29
- const pkg = req(`${name}/package.json`);
46
+ const where = req.resolve(`${name}/package.json`);
47
+ const pkg = req(where);
30
48
  if (maybeMeta(pkg)) {
31
49
  const vr = (0, semver_1.getSemverRange)(ver);
32
50
  if (typeof pkg.version === "string" &&
33
51
  (!vr || (0, semver_2.satisfies)(pkg.version, vr))) {
52
+ pkg._where = where;
34
53
  return pkg;
35
54
  }
36
55
  }
@@ -54,85 +73,91 @@ function getMetaFromNpm(name, ver) {
54
73
  (parsed.type === "range" ||
55
74
  parsed.type === "version" ||
56
75
  parsed.type === "tag")) {
57
- return getMetaFromNpmView(parsed.name, (_a = parsed.fetchSpec) === null || _a === void 0 ? void 0 : _a.trim());
76
+ return getMetaFromNameAndSpec(parsed.name, (_a = parsed.fetchSpec) === null || _a === void 0 ? void 0 : _a.trim());
58
77
  }
59
78
  }
60
79
  if (trimmed.includes("/") || trimmed.includes(":")) {
61
80
  return { cache: [], get: () => [] };
62
81
  }
63
- return getMetaFromNpmView(name, ver.trim());
82
+ return getMetaFromNameAndSpec(name, ver.trim());
64
83
  }
65
84
  exports.getMetaFromNpm = getMetaFromNpm;
66
- function getMetaFromNpmView(name, verOrTag) {
67
- const range = (0, semver_1.getSemverRange)(verOrTag);
85
+ function getMetaFromNameAndSpec(name, verOrTag) {
86
+ const cachedFilePath = path_1.default.join(CACHED_META_ROOT, `${name}.json`);
87
+ const { cache, get } = getMetaFromName(name, cachedFilePath);
88
+ let isTargetVersion;
89
+ let hasUnknown = false;
90
+ const range = (0, semver_1.getSemverRange)(verOrTag || "*");
68
91
  if (range) {
69
- const min = (0, semver_2.minVersion)(range);
70
- if (min) {
71
- const isTargetVersion = (meta) => {
92
+ isTargetVersion = (meta) => {
93
+ if (!meta.version) {
94
+ return true;
95
+ }
96
+ return range.test(meta.version);
97
+ };
98
+ }
99
+ else {
100
+ const parsed = npm_package_arg_1.default.resolve(name, verOrTag);
101
+ if (parsed.type === "tag") {
102
+ isTargetVersion = (meta) => {
103
+ var _a;
72
104
  if (!meta.version) {
73
105
  return true;
74
106
  }
75
- return range.test(meta.version);
76
- };
77
- const cachedFilePath = path_1.default.join(CACHED_META_ROOT, `${name}.json`);
78
- const { cache, get } = getMetaFromNpmViewWithPackageArg((minVer) => `${name}@>=${minVer}`, cachedFilePath, min);
79
- if (cache) {
80
- const metaList = cache.data.meta.filter(isTargetVersion);
81
- let alive = cache.alive;
82
- if (!alive) {
83
- const maxNext = (0, semver_1.maxNextVersion)(range);
84
- if (maxNext) {
85
- alive = cache.data.meta.some((m) => m.version && maxNext.compare(m.version) <= 0);
86
- }
87
- }
88
- if (alive) {
89
- return {
90
- cache: metaList,
91
- get: () => metaList,
92
- };
107
+ const v = (_a = meta["dist-tags"]) === null || _a === void 0 ? void 0 : _a[parsed.fetchSpec];
108
+ if (v == null) {
109
+ hasUnknown = true;
93
110
  }
94
- return {
95
- cache: metaList,
96
- get: () => { var _a, _b; return (_b = (_a = get()) === null || _a === void 0 ? void 0 : _a.filter(isTargetVersion)) !== null && _b !== void 0 ? _b : null; },
97
- };
98
- }
111
+ return v === meta.version;
112
+ };
113
+ }
114
+ else {
99
115
  return {
100
116
  cache: [],
101
- get: () => { var _a, _b; return (_b = (_a = get()) === null || _a === void 0 ? void 0 : _a.filter(isTargetVersion)) !== null && _b !== void 0 ? _b : null; },
117
+ get: () => null,
102
118
  };
103
119
  }
104
120
  }
105
- const packageArg = `${name}@${verOrTag || "*"}`;
106
- const cachedFilePath = path_1.default.join(CACHED_META_ROOT, `${packageArg
107
- .replace(/[^\d+\-./<=>@\\^a-z|~]/giu, "_")
108
- .toLowerCase()}.json`);
109
- const { cache, get } = getMetaFromNpmViewWithPackageArg(() => packageArg, cachedFilePath);
110
121
  if (cache) {
111
- if (cache.alive) {
122
+ let alive = cache.alive;
123
+ if (!alive && range) {
124
+ const maxNext = (0, semver_1.maxNextVersion)(range);
125
+ if (maxNext) {
126
+ alive = cache.data.meta.some((m) => m.version && maxNext.compare(m.version) <= 0);
127
+ }
128
+ }
129
+ const metaList = cache.data.meta.filter(isTargetVersion);
130
+ if (alive) {
112
131
  return {
113
- cache: cache.data.meta,
114
- get: () => cache.data.meta,
132
+ cache: metaList,
133
+ get: () => (hasUnknown ? null : metaList),
115
134
  };
116
135
  }
117
136
  return {
118
- cache: cache.data.meta,
119
- get,
137
+ cache: metaList,
138
+ get: () => {
139
+ var _a, _b;
140
+ const list = (_b = (_a = get()) === null || _a === void 0 ? void 0 : _a.filter(isTargetVersion)) !== null && _b !== void 0 ? _b : null;
141
+ return hasUnknown && !(list === null || list === void 0 ? void 0 : list.length) ? null : list;
142
+ },
120
143
  };
121
144
  }
122
145
  return {
123
146
  cache: [],
124
- get,
147
+ get: () => {
148
+ var _a, _b;
149
+ const list = (_b = (_a = get()) === null || _a === void 0 ? void 0 : _a.filter(isTargetVersion)) !== null && _b !== void 0 ? _b : null;
150
+ return hasUnknown && !(list === null || list === void 0 ? void 0 : list.length) ? null : list;
151
+ },
125
152
  };
126
153
  }
127
- function getMetaFromNpmViewWithPackageArg(getPackageArg, cachedFilePath, min) {
128
- let minVer = min === null || min === void 0 ? void 0 : min.version;
154
+ function getMetaFromName(name, cachedFilePath) {
129
155
  const cache = getCache();
130
- if (cache === null || cache === void 0 ? void 0 : cache.data.minVersion) {
131
- minVer = cache.data.minVersion;
132
- }
133
156
  return {
134
- cache: getCache(),
135
- get: () => getMetaFromNpmViewWithPackageArgWithoutCache(getPackageArg(minVer), cachedFilePath, minVer),
157
+ cache,
158
+ get: () => {
159
+ return getMetaFromNameWithoutCache(name, cachedFilePath);
160
+ },
136
161
  };
137
162
  function getCache() {
138
163
  makeDirs(path_1.default.dirname(cachedFilePath));
@@ -143,14 +168,6 @@ function getMetaFromNpmViewWithPackageArg(getPackageArg, cachedFilePath, min) {
143
168
  if (data.meta == null) {
144
169
  return null;
145
170
  }
146
- if (min) {
147
- if (!data.minVersion) {
148
- return null;
149
- }
150
- if (min.compare(data.minVersion) < 0) {
151
- return null;
152
- }
153
- }
154
171
  const alive = Boolean((typeof data.expired === "number" && data.expired >= Date.now()) ||
155
172
  (typeof data.timestamp === "number" &&
156
173
  data.timestamp + TTL >= Date.now()) ||
@@ -161,19 +178,23 @@ function getMetaFromNpmViewWithPackageArg(getPackageArg, cachedFilePath, min) {
161
178
  };
162
179
  }
163
180
  }
164
- function getMetaFromNpmViewWithPackageArgWithoutCache(packageArg, cachedFilePath, minVer) {
181
+ function getMetaFromNameWithoutCache(name, cachedFilePath) {
165
182
  let meta = [];
166
183
  try {
167
- const json = exec("npm", [
168
- "view",
169
- `${packageArg}`,
170
- ...NPM_INFO_PROPERTIES,
171
- "--json",
172
- ]);
173
- meta = JSON.parse(json);
174
- if (!Array.isArray(meta)) {
175
- meta = [meta];
176
- }
184
+ const allMeta = (0, package_json_1.syncPackageJson)(name, {
185
+ allVersions: true,
186
+ });
187
+ meta = Object.values(allMeta.versions).map((vm) => {
188
+ return {
189
+ version: vm.version,
190
+ engines: vm.engines,
191
+ dependencies: vm.dependencies,
192
+ peerDependencies: vm.peerDependencies,
193
+ optionalDependencies: vm.optionalDependencies,
194
+ "dist-tags": allMeta["dist-tags"],
195
+ deprecated: vm.deprecated,
196
+ };
197
+ });
177
198
  }
178
199
  catch (e) {
179
200
  return null;
@@ -183,7 +204,6 @@ function getMetaFromNpmViewWithPackageArgWithoutCache(packageArg, cachedFilePath
183
204
  meta,
184
205
  timestamp,
185
206
  expired: timestamp + Math.floor(Math.random() * 1000 * 60),
186
- minVersion: minVer,
187
207
  };
188
208
  fs_1.default.writeFileSync(cachedFilePath, JSON.stringify(content));
189
209
  delete require.cache[cachedFilePath];
@@ -233,19 +253,6 @@ function makeDirs(dir) {
233
253
  fs_1.default.mkdirSync(d);
234
254
  }
235
255
  }
236
- function exec(command, args) {
237
- const result = (0, child_process_1.spawnSync)(command, args, {
238
- windowsHide: true,
239
- maxBuffer: Infinity,
240
- });
241
- if (result.error) {
242
- throw result.error;
243
- }
244
- if (result.status !== 0) {
245
- throw new Error(`Failed:\n${result.stdout.toString()}\n${result.stderr.toString()}`);
246
- }
247
- return result.stdout.toString("utf8");
248
- }
249
256
  function getCwd(context) {
250
257
  if (context.getCwd) {
251
258
  return context.getCwd();
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.syncPackageJson = void 0;
4
+ const synckit_1 = require("synckit");
5
+ exports.syncPackageJson = (0, synckit_1.createSyncFn)(require.resolve("./worker"));
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const synckit_1 = require("synckit");
16
+ const tunnel_agent_1 = __importDefault(require("tunnel-agent"));
17
+ const dynamicImport = new Function("m", "return import(m)");
18
+ (0, synckit_1.runAsWorker)((packageName, options) => __awaiter(void 0, void 0, void 0, function* () {
19
+ const m = yield dynamicImport("package-json");
20
+ const packageJson = (m === null || m === void 0 ? void 0 : m.default) || m;
21
+ return packageJson(packageName, withAutoProxy(options));
22
+ }));
23
+ function withAutoProxy(options) {
24
+ const PROXY_ENV = [
25
+ "https_proxy",
26
+ "HTTPS_PROXY",
27
+ "http_proxy",
28
+ "HTTP_PROXY",
29
+ "npm_config_https_proxy",
30
+ "npm_config_http_proxy",
31
+ ];
32
+ const proxyStr = PROXY_ENV.map((k) => process.env[k]).find((v) => v);
33
+ if (proxyStr) {
34
+ const proxyUrl = new URL(proxyStr);
35
+ const tunnelOption = {
36
+ proxy: {
37
+ host: proxyUrl.hostname,
38
+ port: Number(proxyUrl.port),
39
+ proxyAuth: proxyUrl.username || proxyUrl.password
40
+ ? `${proxyUrl.username}:${proxyUrl.password}`
41
+ : undefined,
42
+ },
43
+ };
44
+ const httpAgent = tunnel_agent_1.default[`httpOverHttp${proxyUrl.protocol === "https:" ? "s" : ""}`](tunnelOption);
45
+ const httpsAgent = tunnel_agent_1.default[`httpsOverHttp${proxyUrl.protocol === "https:" ? "s" : ""}`](tunnelOption);
46
+ return Object.assign({ agent: { http: httpAgent, https: httpsAgent } }, options);
47
+ }
48
+ return options;
49
+ }
@@ -7,12 +7,20 @@ exports.rules = void 0;
7
7
  const absolute_version_1 = __importDefault(require("../rules/absolute-version"));
8
8
  const compat_engines_1 = __importDefault(require("../rules/compat-engines"));
9
9
  const no_deprecated_1 = __importDefault(require("../rules/no-deprecated"));
10
+ const no_dupe_deps_1 = __importDefault(require("../rules/no-dupe-deps"));
11
+ const no_restricted_deps_1 = __importDefault(require("../rules/no-restricted-deps"));
12
+ const prefer_caret_range_version_1 = __importDefault(require("../rules/prefer-caret-range-version"));
13
+ const prefer_tilde_range_version_1 = __importDefault(require("../rules/prefer-tilde-range-version"));
10
14
  const valid_engines_1 = __importDefault(require("../rules/valid-engines"));
11
15
  const valid_semver_1 = __importDefault(require("../rules/valid-semver"));
12
16
  exports.rules = [
13
17
  absolute_version_1.default,
14
18
  compat_engines_1.default,
15
19
  no_deprecated_1.default,
20
+ no_dupe_deps_1.default,
21
+ no_restricted_deps_1.default,
22
+ prefer_caret_range_version_1.default,
23
+ prefer_tilde_range_version_1.default,
16
24
  valid_engines_1.default,
17
25
  valid_semver_1.default,
18
26
  ];
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.iterateSemverRanges = void 0;
4
+ const semver_1 = require("./semver");
5
+ function* iterateSemverRanges(versionRanges) {
6
+ let startOffset = 0;
7
+ for (const strRange of versionRanges.split("||")) {
8
+ const result = toRangeResult(strRange, startOffset);
9
+ if (result) {
10
+ yield result;
11
+ }
12
+ startOffset += strRange.length + 2;
13
+ }
14
+ }
15
+ exports.iterateSemverRanges = iterateSemverRanges;
16
+ function toRangeResult(strRange, startOffset) {
17
+ let start = 0;
18
+ while (strRange.length > start && !strRange[start].trim()) {
19
+ start++;
20
+ }
21
+ let end = strRange.length;
22
+ while (end > start && !strRange[end - 1].trim()) {
23
+ end--;
24
+ }
25
+ const value = strRange.slice(start, end);
26
+ const range = (0, semver_1.getSemverRange)(value);
27
+ if (!range) {
28
+ return null;
29
+ }
30
+ if (range.set.length !== 1) {
31
+ return null;
32
+ }
33
+ return {
34
+ value,
35
+ comparators: range.set[0],
36
+ range: [startOffset + start, startOffset + end],
37
+ };
38
+ }
package/package.json CHANGED
@@ -1,101 +1,104 @@
1
1
  {
2
- "name": "eslint-plugin-node-dependencies",
3
- "version": "0.7.0",
4
- "description": "ESLint plugin to check Node.js dependencies.",
5
- "engines": {
6
- "node": "^12 || >=14"
7
- },
8
- "main": "dist/index.js",
9
- "files": [
10
- "dist"
11
- ],
12
- "scripts": {
13
- "prebuild": "npm run -s clean",
14
- "build": "tsc --project ./tsconfig.build.json",
15
- "clean": "rimraf .nyc_output dist coverage",
16
- "lint": "eslint . --ext .js,.vue,.ts,.json,.yaml,.yml",
17
- "eslint-fix": "eslint . --ext .js,.vue,.ts,.json,.yaml,.yml --fix",
18
- "pretest": "npm run build",
19
- "test:base": "mocha --require ts-node/register \"tests/**/*.ts\" --reporter dot --timeout 60000",
20
- "test": "npm run test:nyc",
21
- "test:nyc": "nyc --reporter=lcov npm run test:base",
22
- "test:debug": "mocha --require ts-node/register/transpile-only \"tests/**/*.ts\" --reporter dot --timeout 60000",
23
- "test:watch": "npm run test:base -- --watch",
24
- "update": "ts-node --transpile-only ./tools/update.ts && npm run eslint-fix",
25
- "new": "ts-node ./tools/new-rule.ts",
26
- "docs:watch": "vuepress dev --debug docs",
27
- "docs:build": "npm run build && vuepress build docs --no-cache",
28
- "preversion": "npm test && git add .",
29
- "version": "env-cmd -e version npm run update && git add ."
30
- },
31
- "repository": {
32
- "type": "git",
33
- "url": "git+https://github.com/ota-meshi/eslint-plugin-node-dependencies.git"
34
- },
35
- "keywords": [
36
- "eslint",
37
- "eslintplugin",
38
- "eslint-plugin",
39
- "nodejs",
40
- "dependencies",
41
- "json"
42
- ],
43
- "author": "Yosuke Ota (https://github.com/ota-meshi)",
44
- "funding": "https://github.com/sponsors/ota-meshi",
45
- "license": "MIT",
46
- "bugs": {
47
- "url": "https://github.com/ota-meshi/eslint-plugin-node-dependencies/issues"
48
- },
49
- "homepage": "https://github.com/ota-meshi/eslint-plugin-node-dependencies#readme",
50
- "peerDependencies": {
51
- "eslint": ">=6.0.0"
52
- },
53
- "devDependencies": {
54
- "@ota-meshi/eslint-plugin": "^0.10.0",
55
- "@types/chai": "^4.2.18",
56
- "@types/eslint": "^8.0.0",
57
- "@types/eslint-scope": "^3.7.0",
58
- "@types/eslint-visitor-keys": "^1.0.0",
59
- "@types/estree": "^0.0.51",
60
- "@types/mocha": "^9.0.0",
61
- "@types/node": "^16.0.0",
62
- "@types/npm-package-arg": "^6.1.1",
63
- "@types/semver": "^7.3.8",
64
- "@typescript-eslint/eslint-plugin": "^5.0.0",
65
- "@typescript-eslint/parser": "^5.0.0",
66
- "chai": "^4.3.4",
67
- "env-cmd": "^10.1.0",
68
- "eslint": "^8.0.0",
69
- "eslint-config-prettier": "^8.0.0",
70
- "eslint-plugin-eslint-comments": "^3.2.0",
71
- "eslint-plugin-eslint-plugin": "^4.0.0",
72
- "eslint-plugin-json-schema-validator": "^2.0.0",
73
- "eslint-plugin-jsonc": "^2.0.0",
74
- "eslint-plugin-node": "^11.1.0",
75
- "eslint-plugin-node-dependencies": "^0.6.0",
76
- "eslint-plugin-prettier": "^4.0.0",
77
- "eslint-plugin-regexp": "^1.0.0",
78
- "eslint-plugin-vue": "^8.0.0",
79
- "eslint-plugin-yml": "^0.14.0",
80
- "eslint4b": "^7.3.1",
81
- "mocha": "^9.0.0",
82
- "mocha-chai-jest-snapshot": "^1.1.2",
83
- "nyc": "^15.1.0",
84
- "prettier": "^2.0.5",
85
- "raw-loader": "^4.0.1",
86
- "stylelint": "^14.0.0",
87
- "stylelint-config-recommended-vue": "^1.0.0",
88
- "stylelint-config-standard": "^25.0.0",
89
- "stylelint-plugin-stylus": "^0.13.0",
90
- "ts-node": "^10.0.0",
91
- "typescript": "^4.0.0",
92
- "vue-eslint-editor": "^1.1.0",
93
- "vue-eslint-parser": "^8.0.0",
94
- "vuepress": "^1.5.2"
95
- },
96
- "dependencies": {
97
- "jsonc-eslint-parser": "^1 || ^2.0.2",
98
- "npm-package-arg": "^8.1.5",
99
- "semver": "^7.3.5"
100
- }
2
+ "name": "eslint-plugin-node-dependencies",
3
+ "version": "0.9.1",
4
+ "description": "ESLint plugin to check Node.js dependencies.",
5
+ "engines": {
6
+ "node": ">=14.17.0"
7
+ },
8
+ "main": "dist/index.js",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "prebuild": "npm run -s clean",
14
+ "build": "tsc --project ./tsconfig.build.json",
15
+ "clean": "rimraf .nyc_output dist coverage",
16
+ "lint": "eslint . --ext .js,.vue,.ts,.json,.yaml,.yml",
17
+ "eslint-fix": "eslint . --ext .js,.vue,.ts,.json,.yaml,.yml --fix",
18
+ "pretest": "npm run build",
19
+ "test:base": "mocha --require ts-node/register \"tests/**/*.ts\" --reporter dot --timeout 60000",
20
+ "test": "npm run test:nyc",
21
+ "test:nyc": "nyc --reporter=lcov npm run test:base",
22
+ "test:debug": "mocha --require ts-node/register/transpile-only \"tests/**/*.ts\" --reporter dot --timeout 60000",
23
+ "test:watch": "npm run test:base -- --watch",
24
+ "update": "ts-node --transpile-only ./tools/update.ts && npm run eslint-fix",
25
+ "new": "ts-node ./tools/new-rule.ts",
26
+ "docs:watch": "export NODE_OPTIONS=--openssl-legacy-provider && vuepress dev --debug docs",
27
+ "docs:build": "export NODE_OPTIONS=--openssl-legacy-provider && npm run build && vuepress build docs --no-cache",
28
+ "preversion": "npm test && git add .",
29
+ "version": "env-cmd -e version npm run update && git add ."
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/ota-meshi/eslint-plugin-node-dependencies.git"
34
+ },
35
+ "keywords": [
36
+ "eslint",
37
+ "eslintplugin",
38
+ "eslint-plugin",
39
+ "nodejs",
40
+ "dependencies",
41
+ "json"
42
+ ],
43
+ "author": "Yosuke Ota (https://github.com/ota-meshi)",
44
+ "funding": "https://github.com/sponsors/ota-meshi",
45
+ "license": "MIT",
46
+ "bugs": {
47
+ "url": "https://github.com/ota-meshi/eslint-plugin-node-dependencies/issues"
48
+ },
49
+ "homepage": "https://github.com/ota-meshi/eslint-plugin-node-dependencies#readme",
50
+ "peerDependencies": {
51
+ "eslint": ">=6.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "@ota-meshi/eslint-plugin": "^0.11.0",
55
+ "@types/chai": "^4.2.18",
56
+ "@types/eslint": "^8.0.0",
57
+ "@types/eslint-scope": "^3.7.0",
58
+ "@types/eslint-visitor-keys": "^1.0.0",
59
+ "@types/estree": "^0.0.52",
60
+ "@types/mocha": "^9.0.0",
61
+ "@types/node": "^16.0.0",
62
+ "@types/npm-package-arg": "^6.1.1",
63
+ "@types/semver": "^7.3.8",
64
+ "@typescript-eslint/eslint-plugin": "^5.0.0",
65
+ "@typescript-eslint/parser": "^5.0.0",
66
+ "chai": "^4.3.4",
67
+ "env-cmd": "^10.1.0",
68
+ "eslint": "^8.0.0",
69
+ "eslint-config-prettier": "^8.0.0",
70
+ "eslint-plugin-eslint-comments": "^3.2.0",
71
+ "eslint-plugin-eslint-plugin": "^4.0.0",
72
+ "eslint-plugin-json-schema-validator": "^3.0.0",
73
+ "eslint-plugin-jsonc": "^2.0.0",
74
+ "eslint-plugin-node": "^11.1.0",
75
+ "eslint-plugin-node-dependencies": "^0.9.0",
76
+ "eslint-plugin-prettier": "^4.0.0",
77
+ "eslint-plugin-regexp": "^1.0.0",
78
+ "eslint-plugin-vue": "^9.0.0",
79
+ "eslint-plugin-yml": "^1.0.0",
80
+ "eslint4b": "^7.3.1",
81
+ "mocha": "^10.0.0",
82
+ "mocha-chai-jest-snapshot": "^1.1.2",
83
+ "nyc": "^15.1.0",
84
+ "prettier": "^2.0.5",
85
+ "raw-loader": "^4.0.1",
86
+ "stylelint": "^14.0.0",
87
+ "stylelint-config-recommended-vue": "^1.0.0",
88
+ "stylelint-config-standard": "^26.0.0",
89
+ "stylelint-stylus": "^0.16.0",
90
+ "ts-node": "^10.0.0",
91
+ "typescript": "^4.0.0",
92
+ "vue-eslint-editor": "^1.1.0",
93
+ "vue-eslint-parser": "^9.0.0",
94
+ "vuepress": "^1.5.2"
95
+ },
96
+ "dependencies": {
97
+ "jsonc-eslint-parser": "^2.0.2",
98
+ "npm-package-arg": "^9.0.0",
99
+ "package-json": "^8.1.0",
100
+ "semver": "^7.3.5",
101
+ "synckit": "^0.7.1",
102
+ "tunnel-agent": "^0.6.0"
103
+ }
101
104
  }