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.
Files changed (69) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +189 -0
  3. package/lib/configs/_commons.js +76 -0
  4. package/lib/configs/recommended-module.js +27 -0
  5. package/lib/configs/recommended-script.js +24 -0
  6. package/lib/configs/recommended.js +18 -0
  7. package/lib/index.js +55 -0
  8. package/lib/rules/callback-return.js +185 -0
  9. package/lib/rules/exports-style.js +297 -0
  10. package/lib/rules/file-extension-in-import.js +129 -0
  11. package/lib/rules/global-require.js +91 -0
  12. package/lib/rules/handle-callback-err.js +94 -0
  13. package/lib/rules/no-callback-literal.js +82 -0
  14. package/lib/rules/no-deprecated-api.js +782 -0
  15. package/lib/rules/no-exports-assign.js +75 -0
  16. package/lib/rules/no-extraneous-import.js +49 -0
  17. package/lib/rules/no-extraneous-require.js +49 -0
  18. package/lib/rules/no-hide-core-modules.js +157 -0
  19. package/lib/rules/no-missing-import.js +47 -0
  20. package/lib/rules/no-missing-require.js +47 -0
  21. package/lib/rules/no-mixed-requires.js +255 -0
  22. package/lib/rules/no-new-require.js +39 -0
  23. package/lib/rules/no-path-concat.js +212 -0
  24. package/lib/rules/no-process-env.js +45 -0
  25. package/lib/rules/no-process-exit.js +36 -0
  26. package/lib/rules/no-restricted-import.js +61 -0
  27. package/lib/rules/no-restricted-require.js +61 -0
  28. package/lib/rules/no-sync.js +53 -0
  29. package/lib/rules/no-unpublished-bin.js +97 -0
  30. package/lib/rules/no-unpublished-import.js +49 -0
  31. package/lib/rules/no-unpublished-require.js +49 -0
  32. package/lib/rules/no-unsupported-features/es-builtins.js +181 -0
  33. package/lib/rules/no-unsupported-features/es-syntax.js +659 -0
  34. package/lib/rules/no-unsupported-features/node-builtins.js +417 -0
  35. package/lib/rules/no-unsupported-features.js +1542 -0
  36. package/lib/rules/prefer-global/buffer.js +49 -0
  37. package/lib/rules/prefer-global/console.js +46 -0
  38. package/lib/rules/prefer-global/process.js +46 -0
  39. package/lib/rules/prefer-global/text-decoder.js +49 -0
  40. package/lib/rules/prefer-global/text-encoder.js +49 -0
  41. package/lib/rules/prefer-global/url-search-params.js +49 -0
  42. package/lib/rules/prefer-global/url.js +48 -0
  43. package/lib/rules/prefer-promises/dns.js +74 -0
  44. package/lib/rules/prefer-promises/fs.js +76 -0
  45. package/lib/rules/process-exit-as-throw.js +164 -0
  46. package/lib/rules/shebang.js +170 -0
  47. package/lib/util/cache.js +58 -0
  48. package/lib/util/check-existence.js +40 -0
  49. package/lib/util/check-extraneous.js +52 -0
  50. package/lib/util/check-prefer-global.js +63 -0
  51. package/lib/util/check-publish.js +71 -0
  52. package/lib/util/check-restricted.js +109 -0
  53. package/lib/util/check-unsupported-builtins.js +108 -0
  54. package/lib/util/enumerate-property-names.js +39 -0
  55. package/lib/util/exists.js +58 -0
  56. package/lib/util/get-allow-modules.js +47 -0
  57. package/lib/util/get-configured-node-version.js +39 -0
  58. package/lib/util/get-convert-path.js +189 -0
  59. package/lib/util/get-npmignore.js +184 -0
  60. package/lib/util/get-package-json.js +75 -0
  61. package/lib/util/get-resolve-paths.js +44 -0
  62. package/lib/util/get-semver-range.js +30 -0
  63. package/lib/util/get-try-extensions.js +47 -0
  64. package/lib/util/import-target.js +85 -0
  65. package/lib/util/merge-visitors-in-place.js +46 -0
  66. package/lib/util/strip-import-path-params.js +10 -0
  67. package/lib/util/visit-import.js +66 -0
  68. package/lib/util/visit-require.js +60 -0
  69. 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
+ }