eslint-plugin-n 14.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 +22 -0
- package/README.md +189 -0
- package/lib/configs/_commons.js +76 -0
- package/lib/configs/recommended-module.js +27 -0
- package/lib/configs/recommended-script.js +24 -0
- package/lib/configs/recommended.js +18 -0
- package/lib/index.js +55 -0
- package/lib/rules/callback-return.js +185 -0
- package/lib/rules/exports-style.js +297 -0
- package/lib/rules/file-extension-in-import.js +129 -0
- package/lib/rules/global-require.js +91 -0
- package/lib/rules/handle-callback-err.js +94 -0
- package/lib/rules/no-callback-literal.js +82 -0
- package/lib/rules/no-deprecated-api.js +782 -0
- package/lib/rules/no-exports-assign.js +75 -0
- package/lib/rules/no-extraneous-import.js +49 -0
- package/lib/rules/no-extraneous-require.js +49 -0
- package/lib/rules/no-hide-core-modules.js +157 -0
- package/lib/rules/no-missing-import.js +47 -0
- package/lib/rules/no-missing-require.js +47 -0
- package/lib/rules/no-mixed-requires.js +255 -0
- package/lib/rules/no-new-require.js +39 -0
- package/lib/rules/no-path-concat.js +212 -0
- package/lib/rules/no-process-env.js +45 -0
- package/lib/rules/no-process-exit.js +36 -0
- package/lib/rules/no-restricted-import.js +61 -0
- package/lib/rules/no-restricted-require.js +61 -0
- package/lib/rules/no-sync.js +53 -0
- package/lib/rules/no-unpublished-bin.js +97 -0
- package/lib/rules/no-unpublished-import.js +49 -0
- package/lib/rules/no-unpublished-require.js +49 -0
- package/lib/rules/no-unsupported-features/es-builtins.js +181 -0
- package/lib/rules/no-unsupported-features/es-syntax.js +659 -0
- package/lib/rules/no-unsupported-features/node-builtins.js +417 -0
- package/lib/rules/no-unsupported-features.js +1542 -0
- package/lib/rules/prefer-global/buffer.js +49 -0
- package/lib/rules/prefer-global/console.js +46 -0
- package/lib/rules/prefer-global/process.js +46 -0
- package/lib/rules/prefer-global/text-decoder.js +49 -0
- package/lib/rules/prefer-global/text-encoder.js +49 -0
- package/lib/rules/prefer-global/url-search-params.js +49 -0
- package/lib/rules/prefer-global/url.js +48 -0
- package/lib/rules/prefer-promises/dns.js +74 -0
- package/lib/rules/prefer-promises/fs.js +76 -0
- package/lib/rules/process-exit-as-throw.js +164 -0
- package/lib/rules/shebang.js +170 -0
- package/lib/util/cache.js +58 -0
- package/lib/util/check-existence.js +40 -0
- package/lib/util/check-extraneous.js +52 -0
- package/lib/util/check-prefer-global.js +63 -0
- package/lib/util/check-publish.js +71 -0
- package/lib/util/check-restricted.js +109 -0
- package/lib/util/check-unsupported-builtins.js +108 -0
- package/lib/util/enumerate-property-names.js +39 -0
- package/lib/util/exists.js +58 -0
- package/lib/util/get-allow-modules.js +47 -0
- package/lib/util/get-configured-node-version.js +39 -0
- package/lib/util/get-convert-path.js +189 -0
- package/lib/util/get-npmignore.js +184 -0
- package/lib/util/get-package-json.js +75 -0
- package/lib/util/get-resolve-paths.js +44 -0
- package/lib/util/get-semver-range.js +30 -0
- package/lib/util/get-try-extensions.js +47 -0
- package/lib/util/import-target.js +85 -0
- package/lib/util/merge-visitors-in-place.js +46 -0
- package/lib/util/strip-import-path-params.js +10 -0
- package/lib/util/visit-import.js +66 -0
- package/lib/util/visit-require.js +60 -0
- package/package.json +91 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const { CALL, CONSTRUCT, READ } = require("eslint-utils")
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enumerate property names of a given object recursively.
|
|
11
|
+
* @param {object} trackMap The map for APIs to enumerate.
|
|
12
|
+
* @param {string[]|undefined} path The path to the current map.
|
|
13
|
+
* @returns {IterableIterator<string>} The property names of the map.
|
|
14
|
+
*/
|
|
15
|
+
function* enumeratePropertyNames(trackMap, path = []) {
|
|
16
|
+
for (const key of Object.keys(trackMap)) {
|
|
17
|
+
const value = trackMap[key]
|
|
18
|
+
if (typeof value !== "object") {
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
path.push(key)
|
|
23
|
+
|
|
24
|
+
if (value[CALL]) {
|
|
25
|
+
yield `${path.join(".")}()`
|
|
26
|
+
}
|
|
27
|
+
if (value[CONSTRUCT]) {
|
|
28
|
+
yield `new ${path.join(".")}()`
|
|
29
|
+
}
|
|
30
|
+
if (value[READ]) {
|
|
31
|
+
yield path.join(".")
|
|
32
|
+
}
|
|
33
|
+
yield* enumeratePropertyNames(value, path)
|
|
34
|
+
|
|
35
|
+
path.pop()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = enumeratePropertyNames
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const fs = require("fs")
|
|
8
|
+
const path = require("path")
|
|
9
|
+
const Cache = require("./cache")
|
|
10
|
+
|
|
11
|
+
const ROOT = /^(?:[/.]|\.\.|[A-Z]:\\|\\\\)(?:[/\\]\.\.)*$/u
|
|
12
|
+
const cache = new Cache()
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check whether the file exists or not.
|
|
16
|
+
* @param {string} filePath The file path to check.
|
|
17
|
+
* @returns {boolean} `true` if the file exists.
|
|
18
|
+
*/
|
|
19
|
+
function existsCaseSensitive(filePath) {
|
|
20
|
+
let dirPath = filePath
|
|
21
|
+
|
|
22
|
+
while (dirPath !== "" && !ROOT.test(dirPath)) {
|
|
23
|
+
const fileName = path.basename(dirPath)
|
|
24
|
+
dirPath = path.dirname(dirPath)
|
|
25
|
+
|
|
26
|
+
if (fs.readdirSync(dirPath).indexOf(fileName) === -1) {
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Checks whether or not the file of a given path exists.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} filePath - A file path to check.
|
|
38
|
+
* @returns {boolean} `true` if the file of a given path exists.
|
|
39
|
+
*/
|
|
40
|
+
module.exports = function exists(filePath) {
|
|
41
|
+
let result = cache.get(filePath)
|
|
42
|
+
if (result == null) {
|
|
43
|
+
try {
|
|
44
|
+
const relativePath = path.relative(process.cwd(), filePath)
|
|
45
|
+
result =
|
|
46
|
+
fs.statSync(relativePath).isFile() &&
|
|
47
|
+
existsCaseSensitive(relativePath)
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error.code !== "ENOENT") {
|
|
50
|
+
throw error
|
|
51
|
+
}
|
|
52
|
+
result = false
|
|
53
|
+
}
|
|
54
|
+
cache.set(filePath, result)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result
|
|
58
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_VALUE = Object.freeze([])
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Gets `allowModules` property from a given option object.
|
|
11
|
+
*
|
|
12
|
+
* @param {object|undefined} option - An option object to get.
|
|
13
|
+
* @returns {string[]|null} The `allowModules` value, or `null`.
|
|
14
|
+
*/
|
|
15
|
+
function get(option) {
|
|
16
|
+
if (option && option.allowModules && Array.isArray(option.allowModules)) {
|
|
17
|
+
return option.allowModules.map(String)
|
|
18
|
+
}
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gets "allowModules" setting.
|
|
24
|
+
*
|
|
25
|
+
* 1. This checks `options` property, then returns it if exists.
|
|
26
|
+
* 2. This checks `settings.node` property, then returns it if exists.
|
|
27
|
+
* 3. This returns `[]`.
|
|
28
|
+
*
|
|
29
|
+
* @param {RuleContext} context - The rule context.
|
|
30
|
+
* @returns {string[]} A list of extensions.
|
|
31
|
+
*/
|
|
32
|
+
module.exports = function getAllowModules(context) {
|
|
33
|
+
return (
|
|
34
|
+
get(context.options && context.options[0]) ||
|
|
35
|
+
get(context.settings && context.settings.node) ||
|
|
36
|
+
DEFAULT_VALUE
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports.schema = {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: {
|
|
43
|
+
type: "string",
|
|
44
|
+
pattern: "^(?:@[a-zA-Z0-9_\\-.]+/)?[a-zA-Z0-9_\\-.]+$",
|
|
45
|
+
},
|
|
46
|
+
uniqueItems: true,
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const { Range } = require("semver") //eslint-disable-line no-unused-vars
|
|
8
|
+
const getPackageJson = require("./get-package-json")
|
|
9
|
+
const getSemverRange = require("./get-semver-range")
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the `engines.node` field of package.json.
|
|
13
|
+
* @param {string} filename The path to the current linting file.
|
|
14
|
+
* @returns {Range|null} The range object of the `engines.node` field.
|
|
15
|
+
*/
|
|
16
|
+
function getEnginesNode(filename) {
|
|
17
|
+
const info = getPackageJson(filename)
|
|
18
|
+
return getSemverRange(info && info.engines && info.engines.node)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gets version configuration.
|
|
23
|
+
*
|
|
24
|
+
* 1. Parse a given version then return it if it's valid.
|
|
25
|
+
* 2. Look package.json up and parse `engines.node` then return it if it's valid.
|
|
26
|
+
* 3. Return `>=8.0.0`.
|
|
27
|
+
*
|
|
28
|
+
* @param {string|undefined} version The version range text.
|
|
29
|
+
* @param {string} filename The path to the current linting file.
|
|
30
|
+
* This will be used to look package.json up if `version` is not a valid version range.
|
|
31
|
+
* @returns {Range} The configured version range.
|
|
32
|
+
*/
|
|
33
|
+
module.exports = function getConfiguredNodeVersion(version, filename) {
|
|
34
|
+
return (
|
|
35
|
+
getSemverRange(version) ||
|
|
36
|
+
getEnginesNode(filename) ||
|
|
37
|
+
getSemverRange(">=8.0.0")
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const Minimatch = require("minimatch").Minimatch
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {any} x - An any value.
|
|
11
|
+
* @returns {any} Always `x`.
|
|
12
|
+
*/
|
|
13
|
+
function identity(x) {
|
|
14
|
+
return x
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Converts old-style value to new-style value.
|
|
19
|
+
*
|
|
20
|
+
* @param {any} x - The value to convert.
|
|
21
|
+
* @returns {({include: string[], exclude: string[], replace: string[]})[]} Normalized value.
|
|
22
|
+
*/
|
|
23
|
+
function normalizeValue(x) {
|
|
24
|
+
if (Array.isArray(x)) {
|
|
25
|
+
return x
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return Object.keys(x).map(pattern => ({
|
|
29
|
+
include: [pattern],
|
|
30
|
+
exclude: [],
|
|
31
|
+
replace: x[pattern],
|
|
32
|
+
}))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ensures the given value is a string array.
|
|
37
|
+
*
|
|
38
|
+
* @param {any} x - The value to ensure.
|
|
39
|
+
* @returns {string[]} The string array.
|
|
40
|
+
*/
|
|
41
|
+
function toStringArray(x) {
|
|
42
|
+
if (Array.isArray(x)) {
|
|
43
|
+
return x.map(String)
|
|
44
|
+
}
|
|
45
|
+
return []
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates the function which checks whether a file path is matched with the given pattern or not.
|
|
50
|
+
*
|
|
51
|
+
* @param {string[]} includePatterns - The glob patterns to include files.
|
|
52
|
+
* @param {string[]} excludePatterns - The glob patterns to exclude files.
|
|
53
|
+
* @returns {function} Created predicate function.
|
|
54
|
+
*/
|
|
55
|
+
function createMatch(includePatterns, excludePatterns) {
|
|
56
|
+
const include = includePatterns.map(pattern => new Minimatch(pattern))
|
|
57
|
+
const exclude = excludePatterns.map(pattern => new Minimatch(pattern))
|
|
58
|
+
|
|
59
|
+
return filePath =>
|
|
60
|
+
include.some(m => m.match(filePath)) &&
|
|
61
|
+
!exclude.some(m => m.match(filePath))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates a function which replaces a given path.
|
|
66
|
+
*
|
|
67
|
+
* @param {RegExp} fromRegexp - A `RegExp` object to replace.
|
|
68
|
+
* @param {string} toStr - A new string to replace.
|
|
69
|
+
* @returns {function} A function which replaces a given path.
|
|
70
|
+
*/
|
|
71
|
+
function defineConvert(fromRegexp, toStr) {
|
|
72
|
+
return filePath => filePath.replace(fromRegexp, toStr)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Combines given converters.
|
|
77
|
+
* The result function converts a given path with the first matched converter.
|
|
78
|
+
*
|
|
79
|
+
* @param {{match: function, convert: function}} converters - A list of converters to combine.
|
|
80
|
+
* @returns {function} A function which replaces a given path.
|
|
81
|
+
*/
|
|
82
|
+
function combine(converters) {
|
|
83
|
+
return filePath => {
|
|
84
|
+
for (const converter of converters) {
|
|
85
|
+
if (converter.match(filePath)) {
|
|
86
|
+
return converter.convert(filePath)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return filePath
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parses `convertPath` property from a given option object.
|
|
95
|
+
*
|
|
96
|
+
* @param {object|undefined} option - An option object to get.
|
|
97
|
+
* @returns {function|null} A function which converts a path., or `null`.
|
|
98
|
+
*/
|
|
99
|
+
function parse(option) {
|
|
100
|
+
if (
|
|
101
|
+
!option ||
|
|
102
|
+
!option.convertPath ||
|
|
103
|
+
typeof option.convertPath !== "object"
|
|
104
|
+
) {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const converters = []
|
|
109
|
+
for (const pattern of normalizeValue(option.convertPath)) {
|
|
110
|
+
const include = toStringArray(pattern.include)
|
|
111
|
+
const exclude = toStringArray(pattern.exclude)
|
|
112
|
+
const fromRegexp = new RegExp(String(pattern.replace[0]))
|
|
113
|
+
const toStr = String(pattern.replace[1])
|
|
114
|
+
|
|
115
|
+
converters.push({
|
|
116
|
+
match: createMatch(include, exclude),
|
|
117
|
+
convert: defineConvert(fromRegexp, toStr),
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return combine(converters)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Gets "convertPath" setting.
|
|
126
|
+
*
|
|
127
|
+
* 1. This checks `options` property, then returns it if exists.
|
|
128
|
+
* 2. This checks `settings.node` property, then returns it if exists.
|
|
129
|
+
* 3. This returns a function of identity.
|
|
130
|
+
*
|
|
131
|
+
* @param {RuleContext} context - The rule context.
|
|
132
|
+
* @returns {function} A function which converts a path.
|
|
133
|
+
*/
|
|
134
|
+
module.exports = function getConvertPath(context) {
|
|
135
|
+
return (
|
|
136
|
+
parse(context.options && context.options[0]) ||
|
|
137
|
+
parse(context.settings && context.settings.node) ||
|
|
138
|
+
identity
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* JSON Schema for `convertPath` option.
|
|
144
|
+
*/
|
|
145
|
+
module.exports.schema = {
|
|
146
|
+
anyOf: [
|
|
147
|
+
{
|
|
148
|
+
type: "object",
|
|
149
|
+
properties: {},
|
|
150
|
+
patternProperties: {
|
|
151
|
+
"^.+$": {
|
|
152
|
+
type: "array",
|
|
153
|
+
items: { type: "string" },
|
|
154
|
+
minItems: 2,
|
|
155
|
+
maxItems: 2,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
additionalProperties: false,
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
type: "array",
|
|
162
|
+
items: {
|
|
163
|
+
type: "object",
|
|
164
|
+
properties: {
|
|
165
|
+
include: {
|
|
166
|
+
type: "array",
|
|
167
|
+
items: { type: "string" },
|
|
168
|
+
minItems: 1,
|
|
169
|
+
uniqueItems: true,
|
|
170
|
+
},
|
|
171
|
+
exclude: {
|
|
172
|
+
type: "array",
|
|
173
|
+
items: { type: "string" },
|
|
174
|
+
uniqueItems: true,
|
|
175
|
+
},
|
|
176
|
+
replace: {
|
|
177
|
+
type: "array",
|
|
178
|
+
items: { type: "string" },
|
|
179
|
+
minItems: 2,
|
|
180
|
+
maxItems: 2,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
additionalProperties: false,
|
|
184
|
+
required: ["include", "replace"],
|
|
185
|
+
},
|
|
186
|
+
minItems: 1,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const fs = require("fs")
|
|
8
|
+
const path = require("path")
|
|
9
|
+
const ignore = require("ignore")
|
|
10
|
+
const Cache = require("./cache")
|
|
11
|
+
const exists = require("./exists")
|
|
12
|
+
const getPackageJson = require("./get-package-json")
|
|
13
|
+
|
|
14
|
+
const cache = new Cache()
|
|
15
|
+
const SLASH_AT_BEGIN_AND_END = /^!?\/+|^!|\/+$/gu
|
|
16
|
+
const PARENT_RELATIVE_PATH = /^\.\./u
|
|
17
|
+
const NEVER_IGNORED = /^(?:readme\.[^.]*|(?:licen[cs]e|changes|changelog|history)(?:\.[^.]*)?)$/iu
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Checks whether or not a given file name is a relative path to a ancestor
|
|
21
|
+
* directory.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} filePath - A file name to check.
|
|
24
|
+
* @returns {boolean} `true` if the file name is a relative path to a ancestor
|
|
25
|
+
* directory.
|
|
26
|
+
*/
|
|
27
|
+
function isAncestorFiles(filePath) {
|
|
28
|
+
return PARENT_RELATIVE_PATH.test(filePath)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {function} f - A function.
|
|
33
|
+
* @param {function} g - A function.
|
|
34
|
+
* @returns {function} A logical-and function of `f` and `g`.
|
|
35
|
+
*/
|
|
36
|
+
function and(f, g) {
|
|
37
|
+
return filePath => f(filePath) && g(filePath)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {function} f - A function.
|
|
42
|
+
* @param {function} g - A function.
|
|
43
|
+
* @param {function|null} h - A function.
|
|
44
|
+
* @returns {function} A logical-or function of `f`, `g`, and `h`.
|
|
45
|
+
*/
|
|
46
|
+
function or(f, g, h) {
|
|
47
|
+
return filePath => f(filePath) || g(filePath) || (h && h(filePath))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {function} f - A function.
|
|
52
|
+
* @returns {function} A logical-not function of `f`.
|
|
53
|
+
*/
|
|
54
|
+
function not(f) {
|
|
55
|
+
return filePath => !f(filePath)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a function which checks whether or not a given file is ignoreable.
|
|
60
|
+
*
|
|
61
|
+
* @param {object} p - An object of package.json.
|
|
62
|
+
* @returns {function} A function which checks whether or not a given file is ignoreable.
|
|
63
|
+
*/
|
|
64
|
+
function filterNeverIgnoredFiles(p) {
|
|
65
|
+
const basedir = path.dirname(p.filePath)
|
|
66
|
+
const mainFilePath =
|
|
67
|
+
typeof p.main === "string" ? path.join(basedir, p.main) : null
|
|
68
|
+
|
|
69
|
+
return filePath =>
|
|
70
|
+
path.join(basedir, filePath) !== mainFilePath &&
|
|
71
|
+
filePath !== "package.json" &&
|
|
72
|
+
!NEVER_IGNORED.test(path.relative(basedir, filePath))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Creates a function which checks whether or not a given file should be ignored.
|
|
77
|
+
*
|
|
78
|
+
* @param {string[]|null} files - File names of whitelist.
|
|
79
|
+
* @returns {function|null} A function which checks whether or not a given file should be ignored.
|
|
80
|
+
*/
|
|
81
|
+
function parseWhiteList(files) {
|
|
82
|
+
if (!files || !Array.isArray(files)) {
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ig = ignore()
|
|
87
|
+
const igN = ignore()
|
|
88
|
+
let hasN = false
|
|
89
|
+
|
|
90
|
+
for (const file of files) {
|
|
91
|
+
if (typeof file === "string" && file) {
|
|
92
|
+
const body = file.replace(SLASH_AT_BEGIN_AND_END, "")
|
|
93
|
+
if (file.startsWith("!")) {
|
|
94
|
+
igN.add(`${body}`)
|
|
95
|
+
igN.add(`${body}/**`)
|
|
96
|
+
hasN = true
|
|
97
|
+
} else {
|
|
98
|
+
ig.add(`/${body}`)
|
|
99
|
+
ig.add(`/${body}/**`)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return hasN
|
|
105
|
+
? or(ig.createFilter(), not(igN.createFilter()))
|
|
106
|
+
: ig.createFilter()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates a function which checks whether or not a given file should be ignored.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} basedir - The directory path "package.json" exists.
|
|
113
|
+
* @param {boolean} filesFieldExists - `true` if `files` field of `package.json` exists.
|
|
114
|
+
* @returns {function|null} A function which checks whether or not a given file should be ignored.
|
|
115
|
+
*/
|
|
116
|
+
function parseNpmignore(basedir, filesFieldExists) {
|
|
117
|
+
let filePath = path.join(basedir, ".npmignore")
|
|
118
|
+
if (!exists(filePath)) {
|
|
119
|
+
if (filesFieldExists) {
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
filePath = path.join(basedir, ".gitignore")
|
|
124
|
+
if (!exists(filePath)) {
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const ig = ignore()
|
|
130
|
+
ig.add(fs.readFileSync(filePath, "utf8"))
|
|
131
|
+
return not(ig.createFilter())
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Gets an object to check whether a given path should be ignored or not.
|
|
136
|
+
* The object is created from:
|
|
137
|
+
*
|
|
138
|
+
* - `files` field of `package.json`
|
|
139
|
+
* - `.npmignore`
|
|
140
|
+
*
|
|
141
|
+
* @param {string} startPath - A file path to lookup.
|
|
142
|
+
* @returns {object}
|
|
143
|
+
* An object to check whther or not a given path should be ignored.
|
|
144
|
+
* The object has a method `match`.
|
|
145
|
+
* `match` returns `true` if a given file path should be ignored.
|
|
146
|
+
*/
|
|
147
|
+
module.exports = function getNpmignore(startPath) {
|
|
148
|
+
const retv = { match: isAncestorFiles }
|
|
149
|
+
|
|
150
|
+
const p = getPackageJson(startPath)
|
|
151
|
+
if (p) {
|
|
152
|
+
const data = cache.get(p.filePath)
|
|
153
|
+
if (data) {
|
|
154
|
+
return data
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const filesIgnore = parseWhiteList(p.files)
|
|
158
|
+
const npmignoreIgnore = parseNpmignore(
|
|
159
|
+
path.dirname(p.filePath),
|
|
160
|
+
Boolean(filesIgnore)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if (filesIgnore && npmignoreIgnore) {
|
|
164
|
+
retv.match = and(
|
|
165
|
+
filterNeverIgnoredFiles(p),
|
|
166
|
+
or(isAncestorFiles, filesIgnore, npmignoreIgnore)
|
|
167
|
+
)
|
|
168
|
+
} else if (filesIgnore) {
|
|
169
|
+
retv.match = and(
|
|
170
|
+
filterNeverIgnoredFiles(p),
|
|
171
|
+
or(isAncestorFiles, filesIgnore)
|
|
172
|
+
)
|
|
173
|
+
} else if (npmignoreIgnore) {
|
|
174
|
+
retv.match = and(
|
|
175
|
+
filterNeverIgnoredFiles(p),
|
|
176
|
+
or(isAncestorFiles, npmignoreIgnore)
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
cache.set(p.filePath, retv)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return retv
|
|
184
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const fs = require("fs")
|
|
8
|
+
const path = require("path")
|
|
9
|
+
const Cache = require("./cache")
|
|
10
|
+
|
|
11
|
+
const cache = new Cache()
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Reads the `package.json` data in a given path.
|
|
15
|
+
*
|
|
16
|
+
* Don't cache the data.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} dir - The path to a directory to read.
|
|
19
|
+
* @returns {object|null} The read `package.json` data, or null.
|
|
20
|
+
*/
|
|
21
|
+
function readPackageJson(dir) {
|
|
22
|
+
const filePath = path.join(dir, "package.json")
|
|
23
|
+
try {
|
|
24
|
+
const text = fs.readFileSync(filePath, "utf8")
|
|
25
|
+
const data = JSON.parse(text)
|
|
26
|
+
|
|
27
|
+
if (typeof data === "object" && data !== null) {
|
|
28
|
+
data.filePath = filePath
|
|
29
|
+
return data
|
|
30
|
+
}
|
|
31
|
+
} catch (_err) {
|
|
32
|
+
// do nothing.
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Gets a `package.json` data.
|
|
40
|
+
* The data is cached if found, then it's used after.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} [startPath] - A file path to lookup.
|
|
43
|
+
* @returns {object|null} A found `package.json` data or `null`.
|
|
44
|
+
* This object have additional property `filePath`.
|
|
45
|
+
*/
|
|
46
|
+
module.exports = function getPackageJson(startPath = "a.js") {
|
|
47
|
+
const startDir = path.dirname(path.resolve(startPath))
|
|
48
|
+
let dir = startDir
|
|
49
|
+
let prevDir = ""
|
|
50
|
+
let data = null
|
|
51
|
+
|
|
52
|
+
do {
|
|
53
|
+
data = cache.get(dir)
|
|
54
|
+
if (data) {
|
|
55
|
+
if (dir !== startDir) {
|
|
56
|
+
cache.set(startDir, data)
|
|
57
|
+
}
|
|
58
|
+
return data
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
data = readPackageJson(dir)
|
|
62
|
+
if (data) {
|
|
63
|
+
cache.set(dir, data)
|
|
64
|
+
cache.set(startDir, data)
|
|
65
|
+
return data
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Go to next.
|
|
69
|
+
prevDir = dir
|
|
70
|
+
dir = path.resolve(dir, "..")
|
|
71
|
+
} while (dir !== prevDir)
|
|
72
|
+
|
|
73
|
+
cache.set(startDir, null)
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_VALUE = Object.freeze([])
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Gets `resolvePaths` property from a given option object.
|
|
11
|
+
*
|
|
12
|
+
* @param {object|undefined} option - An option object to get.
|
|
13
|
+
* @returns {string[]|null} The `allowModules` value, or `null`.
|
|
14
|
+
*/
|
|
15
|
+
function get(option) {
|
|
16
|
+
if (option && option.resolvePaths && Array.isArray(option.resolvePaths)) {
|
|
17
|
+
return option.resolvePaths.map(String)
|
|
18
|
+
}
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gets "resolvePaths" setting.
|
|
24
|
+
*
|
|
25
|
+
* 1. This checks `options` property, then returns it if exists.
|
|
26
|
+
* 2. This checks `settings.node` property, then returns it if exists.
|
|
27
|
+
* 3. This returns `[]`.
|
|
28
|
+
*
|
|
29
|
+
* @param {RuleContext} context - The rule context.
|
|
30
|
+
* @returns {string[]} A list of extensions.
|
|
31
|
+
*/
|
|
32
|
+
module.exports = function getResolvePaths(context, optionIndex = 0) {
|
|
33
|
+
return (
|
|
34
|
+
get(context.options && context.options[optionIndex]) ||
|
|
35
|
+
get(context.settings && context.settings.node) ||
|
|
36
|
+
DEFAULT_VALUE
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports.schema = {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: { type: "string" },
|
|
43
|
+
uniqueItems: true,
|
|
44
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
3
|
+
* See LICENSE file in root directory for full license.
|
|
4
|
+
*/
|
|
5
|
+
"use strict"
|
|
6
|
+
|
|
7
|
+
const { Range } = require("semver")
|
|
8
|
+
const cache = new Map()
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the `semver.Range` object of a given range text.
|
|
12
|
+
* @param {string} x The text expression for a semver range.
|
|
13
|
+
* @returns {Range|null} The range object of a given range text.
|
|
14
|
+
* It's null if the `x` is not a valid range text.
|
|
15
|
+
*/
|
|
16
|
+
module.exports = function getSemverRange(x) {
|
|
17
|
+
const s = String(x)
|
|
18
|
+
let ret = cache.get(s) || null
|
|
19
|
+
|
|
20
|
+
if (!ret) {
|
|
21
|
+
try {
|
|
22
|
+
ret = new Range(s)
|
|
23
|
+
} catch (_error) {
|
|
24
|
+
// Ignore parsing error.
|
|
25
|
+
}
|
|
26
|
+
cache.set(s, ret)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return ret
|
|
30
|
+
}
|