拿掉 build files

This commit is contained in:
2022-07-18 16:33:23 +08:00
parent 41e2287bcb
commit 3707f158a3
31953 changed files with 0 additions and 4411796 deletions
-58
View File
@@ -1,58 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const SKIP_TIME = 5000
/**
* The class of cache.
* The cache will dispose of each value if the value has not been accessed
* during 5 seconds.
*/
module.exports = class Cache {
/**
* Initialize this cache instance.
*/
constructor() {
this.map = new Map()
}
/**
* Get the cached value of the given key.
* @param {any} key The key to get.
* @returns {any} The cached value or null.
*/
get(key) {
const entry = this.map.get(key)
const now = Date.now()
if (entry) {
if (entry.expire > now) {
entry.expire = now + SKIP_TIME
return entry.value
}
this.map.delete(key)
}
return null
}
/**
* Set the value of the given key.
* @param {any} key The key to set.
* @param {any} value The value to set.
* @returns {void}
*/
set(key, value) {
const entry = this.map.get(key)
const expire = Date.now() + SKIP_TIME
if (entry) {
entry.value = value
entry.expire = expire
} else {
this.map.set(key, { value, expire })
}
}
}
-40
View File
@@ -1,40 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const exists = require("./exists")
const getAllowModules = require("./get-allow-modules")
/**
* Checks whether or not each requirement target exists.
*
* It looks up the target according to the logic of Node.js.
* See Also: https://nodejs.org/api/modules.html
*
* @param {RuleContext} context - A context to report.
* @param {ImportTarget[]} targets - A list of target information to check.
* @returns {void}
*/
module.exports = function checkForExistence(context, targets) {
const allowed = new Set(getAllowModules(context))
for (const target of targets) {
const missingModule =
target.moduleName != null &&
!allowed.has(target.moduleName) &&
target.filePath == null
const missingFile =
target.moduleName == null && !exists(target.filePath)
if (missingModule || missingFile) {
context.report({
node: target.node,
loc: target.node.loc,
message: '"{{name}}" is not found.',
data: target,
})
}
}
}
-52
View File
@@ -1,52 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const getAllowModules = require("./get-allow-modules")
const getPackageJson = require("./get-package-json")
/**
* Checks whether or not each requirement target is published via package.json.
*
* It reads package.json and checks the target exists in `dependencies`.
*
* @param {RuleContext} context - A context to report.
* @param {string} filePath - The current file path.
* @param {ImportTarget[]} targets - A list of target information to check.
* @returns {void}
*/
module.exports = function checkForExtraneous(context, filePath, targets) {
const packageInfo = getPackageJson(filePath)
if (!packageInfo) {
return
}
const allowed = new Set(getAllowModules(context))
const dependencies = new Set(
[].concat(
Object.keys(packageInfo.dependencies || {}),
Object.keys(packageInfo.devDependencies || {}),
Object.keys(packageInfo.peerDependencies || {}),
Object.keys(packageInfo.optionalDependencies || {})
)
)
for (const target of targets) {
const extraneous =
target.moduleName != null &&
target.filePath != null &&
!dependencies.has(target.moduleName) &&
!allowed.has(target.moduleName)
if (extraneous) {
context.report({
node: target.node,
loc: target.node.loc,
message: '"{{moduleName}}" is extraneous.',
data: target,
})
}
}
}
-63
View File
@@ -1,63 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { ReferenceTracker } = require("eslint-utils")
/**
* Verifier for `prefer-global/*` rules.
*/
class Verifier {
/**
* Initialize this instance.
* @param {RuleContext} context The rule context to report.
* @param {{modules:object,globals:object}} trackMap The track map.
*/
constructor(context, trackMap) {
this.context = context
this.trackMap = trackMap
this.verify =
context.options[0] === "never"
? this.verifyToPreferModules
: this.verifyToPreferGlobals
}
/**
* Verify the code to suggest the use of globals.
* @returns {void}
*/
verifyToPreferGlobals() {
const { context, trackMap } = this
const tracker = new ReferenceTracker(context.getScope(), {
mode: "legacy",
})
for (const { node } of [
...tracker.iterateCjsReferences(trackMap.modules),
...tracker.iterateEsmReferences(trackMap.modules),
]) {
context.report({ node, messageId: "preferGlobal" })
}
}
/**
* Verify the code to suggest the use of modules.
* @returns {void}
*/
verifyToPreferModules() {
const { context, trackMap } = this
const tracker = new ReferenceTracker(context.getScope())
for (const { node } of tracker.iterateGlobalReferences(
trackMap.globals
)) {
context.report({ node, messageId: "preferModule" })
}
}
}
module.exports = function checkForPreferGlobal(context, trackMap) {
new Verifier(context, trackMap).verify()
}
-71
View File
@@ -1,71 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const getAllowModules = require("./get-allow-modules")
const getConvertPath = require("./get-convert-path")
const getNpmignore = require("./get-npmignore")
const getPackageJson = require("./get-package-json")
/**
* Checks whether or not each requirement target is published via package.json.
*
* It reads package.json and checks the target exists in `dependencies`.
*
* @param {RuleContext} context - A context to report.
* @param {string} filePath - The current file path.
* @param {ImportTarget[]} targets - A list of target information to check.
* @returns {void}
*/
module.exports = function checkForPublish(context, filePath, targets) {
const packageInfo = getPackageJson(filePath)
if (!packageInfo) {
return
}
const allowed = new Set(getAllowModules(context))
const convertPath = getConvertPath(context)
const basedir = path.dirname(packageInfo.filePath)
// eslint-disable-next-line func-style
const toRelative = fullPath => {
const retv = path.relative(basedir, fullPath).replace(/\\/gu, "/")
return convertPath(retv)
}
const npmignore = getNpmignore(filePath)
const devDependencies = new Set(
Object.keys(packageInfo.devDependencies || {})
)
const dependencies = new Set(
[].concat(
Object.keys(packageInfo.dependencies || {}),
Object.keys(packageInfo.peerDependencies || {}),
Object.keys(packageInfo.optionalDependencies || {})
)
)
if (!npmignore.match(toRelative(filePath))) {
// This file is published, so this cannot import private files.
for (const target of targets) {
const isPrivateFile =
target.moduleName == null &&
npmignore.match(toRelative(target.filePath))
const isDevPackage =
target.moduleName != null &&
devDependencies.has(target.moduleName) &&
!dependencies.has(target.moduleName) &&
!allowed.has(target.moduleName)
if (isPrivateFile || isDevPackage) {
context.report({
node: target.node,
loc: target.node.loc,
message: '"{{name}}" is not published.',
data: { name: target.moduleName || target.name },
})
}
}
}
}
-109
View File
@@ -1,109 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const { Minimatch } = require("minimatch")
/** @typedef {import("../util/import-target")} ImportTarget */
/**
* @typedef {Object} DefinitionData
* @property {string | string[]} name The name to disallow.
* @property {string} [message] The custom message to show.
*/
/**
* Check if matched or not.
* @param {InstanceType<Minimatch>} matcher The matcher.
* @param {boolean} absolute The flag that the matcher is for absolute paths.
* @param {ImportTarget} importee The importee information.
*/
function match(matcher, absolute, { filePath, name }) {
if (absolute) {
return filePath != null && matcher.match(filePath)
}
return matcher.match(name)
}
/** Restriction. */
class Restriction {
/**
* Initialize this restriction.
* @param {DefinitionData} def The definition of a restriction.
*/
constructor({ name, message }) {
const names = Array.isArray(name) ? name : [name]
const matchers = names.map(raw => {
const negate = raw[0] === "!" && raw[1] !== "("
const pattern = negate ? raw.slice(1) : raw
const absolute = path.isAbsolute(pattern)
const matcher = new Minimatch(pattern, { dot: true })
return { absolute, matcher, negate }
})
this.matchers = matchers
this.message = message ? ` ${message}` : ""
}
/**
* Check if a given importee is disallowed.
* @param {ImportTarget} importee The importee to check.
* @returns {boolean} `true` if the importee is disallowed.
*/
match(importee) {
return this.matchers.reduce(
(ret, { absolute, matcher, negate }) =>
negate
? ret && !match(matcher, absolute, importee)
: ret || match(matcher, absolute, importee),
false
)
}
}
/**
* Create a restriction.
* @param {string | DefinitionData} def A definition.
* @returns {Restriction} Created restriction.
*/
function createRestriction(def) {
if (typeof def === "string") {
return new Restriction({ name: def })
}
return new Restriction(def)
}
/**
* Create restrictions.
* @param {(string | DefinitionData | GlobDefinition)[]} defs Definitions.
* @returns {(Restriction | GlobRestriction)[]} Created restrictions.
*/
function createRestrictions(defs) {
return (defs || []).map(createRestriction)
}
/**
* Checks if given importees are disallowed or not.
* @param {RuleContext} context - A context to report.
* @param {ImportTarget[]} targets - A list of target information to check.
* @returns {void}
*/
module.exports = function checkForRestriction(context, targets) {
const restrictions = createRestrictions(context.options[0])
for (const target of targets) {
const restriction = restrictions.find(r => r.match(target))
if (restriction) {
context.report({
node: target.node,
messageId: "restricted",
data: {
name: target.name,
customMessage: restriction.message,
},
})
}
}
}
-108
View File
@@ -1,108 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { Range, lt, major } = require("semver") //eslint-disable-line no-unused-vars
const { ReferenceTracker } = require("eslint-utils")
const getConfiguredNodeVersion = require("./get-configured-node-version")
const getSemverRange = require("./get-semver-range")
/**
* @typedef {Object} SupportInfo
* @property {string | null} supported The stably supported version. If `null` is present, it hasn't been supported yet.
* @property {string[]} [backported] The backported versions.
* @property {string} [experimental] The added version as experimental.
*/
/**
* Parses the options.
* @param {RuleContext} context The rule context.
* @returns {{version:Range,ignores:Set<string>}} Parsed value.
*/
function parseOptions(context) {
const raw = context.options[0] || {}
const filePath = context.getFilename()
const version = getConfiguredNodeVersion(raw.version, filePath)
const ignores = new Set(raw.ignores || [])
return Object.freeze({ version, ignores })
}
/**
* Check if it has been supported.
* @param {SupportInfo} info The support info.
* @param {Range} configured The configured version range.
*/
function isSupported({ backported, supported }, configured) {
if (
backported &&
backported.length >= 2 &&
!backported.every((v, i) => i === 0 || lt(backported[i - 1], v))
) {
throw new Error("Invalid BackportConfiguration")
}
if (supported == null) {
return false
}
if (backported == null || backported.length === 0) {
return !configured.intersects(getSemverRange(`<${supported}`))
}
return !configured.intersects(
getSemverRange(
[...backported, supported]
.map((v, i) => (i === 0 ? `<${v}` : `>=${major(v)}.0.0 <${v}`))
.join(" || ")
)
)
}
/**
* Get the formatted text of a given supported version.
* @param {SupportInfo} info The support info.
*/
function supportedVersionToString({ backported, supported }) {
if (supported == null) {
return "(none yet)"
}
if (backported == null || backported.length === 0) {
return supported
}
return `${supported} (backported: ^${backported.join(", ^")})`
}
/**
* Verify the code to report unsupported APIs.
* @param {RuleContext} context The rule context.
* @param {{modules:object,globals:object}} trackMap The map for APIs to report.
* @returns {void}
*/
module.exports = function checkUnsupportedBuiltins(context, trackMap) {
const options = parseOptions(context)
const tracker = new ReferenceTracker(context.getScope(), { mode: "legacy" })
const references = [
...tracker.iterateCjsReferences(trackMap.modules || {}),
...tracker.iterateEsmReferences(trackMap.modules || {}),
...tracker.iterateGlobalReferences(trackMap.globals || {}),
]
for (const { node, path, info } of references) {
const name = path.join(".")
const supported = isSupported(info, options.version)
if (!supported && !options.ignores.has(name)) {
context.report({
node,
messageId: "unsupported",
data: {
name,
supported: supportedVersionToString(info),
version: options.version.raw,
},
})
}
}
}
-39
View File
@@ -1,39 +0,0 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
const { CALL, CONSTRUCT, READ } = require("eslint-utils")
/**
* Enumerate property names of a given object recursively.
* @param {object} trackMap The map for APIs to enumerate.
* @param {string[]|undefined} path The path to the current map.
* @returns {IterableIterator<string>} The property names of the map.
*/
function* enumeratePropertyNames(trackMap, path = []) {
for (const key of Object.keys(trackMap)) {
const value = trackMap[key]
if (typeof value !== "object") {
continue
}
path.push(key)
if (value[CALL]) {
yield `${path.join(".")}()`
}
if (value[CONSTRUCT]) {
yield `new ${path.join(".")}()`
}
if (value[READ]) {
yield path.join(".")
}
yield* enumeratePropertyNames(value, path)
path.pop()
}
}
module.exports = enumeratePropertyNames
-58
View File
@@ -1,58 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const fs = require("fs")
const path = require("path")
const Cache = require("./cache")
const ROOT = /^(?:[/.]|\.\.|[A-Z]:\\|\\\\)(?:[/\\]\.\.)*$/u
const cache = new Cache()
/**
* Check whether the file exists or not.
* @param {string} filePath The file path to check.
* @returns {boolean} `true` if the file exists.
*/
function existsCaseSensitive(filePath) {
let dirPath = filePath
while (dirPath !== "" && !ROOT.test(dirPath)) {
const fileName = path.basename(dirPath)
dirPath = path.dirname(dirPath)
if (fs.readdirSync(dirPath).indexOf(fileName) === -1) {
return false
}
}
return true
}
/**
* Checks whether or not the file of a given path exists.
*
* @param {string} filePath - A file path to check.
* @returns {boolean} `true` if the file of a given path exists.
*/
module.exports = function exists(filePath) {
let result = cache.get(filePath)
if (result == null) {
try {
const relativePath = path.relative(process.cwd(), filePath)
result =
fs.statSync(relativePath).isFile() &&
existsCaseSensitive(relativePath)
} catch (error) {
if (error.code !== "ENOENT") {
throw error
}
result = false
}
cache.set(filePath, result)
}
return result
}
-47
View File
@@ -1,47 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const DEFAULT_VALUE = Object.freeze([])
/**
* Gets `allowModules` property from a given option object.
*
* @param {object|undefined} option - An option object to get.
* @returns {string[]|null} The `allowModules` value, or `null`.
*/
function get(option) {
if (option && option.allowModules && Array.isArray(option.allowModules)) {
return option.allowModules.map(String)
}
return null
}
/**
* Gets "allowModules" setting.
*
* 1. This checks `options` property, then returns it if exists.
* 2. This checks `settings.node` property, then returns it if exists.
* 3. This returns `[]`.
*
* @param {RuleContext} context - The rule context.
* @returns {string[]} A list of extensions.
*/
module.exports = function getAllowModules(context) {
return (
get(context.options && context.options[0]) ||
get(context.settings && context.settings.node) ||
DEFAULT_VALUE
)
}
module.exports.schema = {
type: "array",
items: {
type: "string",
pattern: "^(?:@[a-zA-Z0-9_\\-.]+/)?[a-zA-Z0-9_\\-.]+$",
},
uniqueItems: true,
}
@@ -1,39 +0,0 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
const { Range } = require("semver") //eslint-disable-line no-unused-vars
const getPackageJson = require("./get-package-json")
const getSemverRange = require("./get-semver-range")
/**
* Get the `engines.node` field of package.json.
* @param {string} filename The path to the current linting file.
* @returns {Range|null} The range object of the `engines.node` field.
*/
function getEnginesNode(filename) {
const info = getPackageJson(filename)
return getSemverRange(info && info.engines && info.engines.node)
}
/**
* Gets version configuration.
*
* 1. Parse a given version then return it if it's valid.
* 2. Look package.json up and parse `engines.node` then return it if it's valid.
* 3. Return `>=8.0.0`.
*
* @param {string|undefined} version The version range text.
* @param {string} filename The path to the current linting file.
* This will be used to look package.json up if `version` is not a valid version range.
* @returns {Range} The configured version range.
*/
module.exports = function getConfiguredNodeVersion(version, filename) {
return (
getSemverRange(version) ||
getEnginesNode(filename) ||
getSemverRange(">=8.0.0")
)
}
-189
View File
@@ -1,189 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const Minimatch = require("minimatch").Minimatch
/**
* @param {any} x - An any value.
* @returns {any} Always `x`.
*/
function identity(x) {
return x
}
/**
* Converts old-style value to new-style value.
*
* @param {any} x - The value to convert.
* @returns {({include: string[], exclude: string[], replace: string[]})[]} Normalized value.
*/
function normalizeValue(x) {
if (Array.isArray(x)) {
return x
}
return Object.keys(x).map(pattern => ({
include: [pattern],
exclude: [],
replace: x[pattern],
}))
}
/**
* Ensures the given value is a string array.
*
* @param {any} x - The value to ensure.
* @returns {string[]} The string array.
*/
function toStringArray(x) {
if (Array.isArray(x)) {
return x.map(String)
}
return []
}
/**
* Creates the function which checks whether a file path is matched with the given pattern or not.
*
* @param {string[]} includePatterns - The glob patterns to include files.
* @param {string[]} excludePatterns - The glob patterns to exclude files.
* @returns {function} Created predicate function.
*/
function createMatch(includePatterns, excludePatterns) {
const include = includePatterns.map(pattern => new Minimatch(pattern))
const exclude = excludePatterns.map(pattern => new Minimatch(pattern))
return filePath =>
include.some(m => m.match(filePath)) &&
!exclude.some(m => m.match(filePath))
}
/**
* Creates a function which replaces a given path.
*
* @param {RegExp} fromRegexp - A `RegExp` object to replace.
* @param {string} toStr - A new string to replace.
* @returns {function} A function which replaces a given path.
*/
function defineConvert(fromRegexp, toStr) {
return filePath => filePath.replace(fromRegexp, toStr)
}
/**
* Combines given converters.
* The result function converts a given path with the first matched converter.
*
* @param {{match: function, convert: function}} converters - A list of converters to combine.
* @returns {function} A function which replaces a given path.
*/
function combine(converters) {
return filePath => {
for (const converter of converters) {
if (converter.match(filePath)) {
return converter.convert(filePath)
}
}
return filePath
}
}
/**
* Parses `convertPath` property from a given option object.
*
* @param {object|undefined} option - An option object to get.
* @returns {function|null} A function which converts a path., or `null`.
*/
function parse(option) {
if (
!option ||
!option.convertPath ||
typeof option.convertPath !== "object"
) {
return null
}
const converters = []
for (const pattern of normalizeValue(option.convertPath)) {
const include = toStringArray(pattern.include)
const exclude = toStringArray(pattern.exclude)
const fromRegexp = new RegExp(String(pattern.replace[0])) //eslint-disable-line require-unicode-regexp
const toStr = String(pattern.replace[1])
converters.push({
match: createMatch(include, exclude),
convert: defineConvert(fromRegexp, toStr),
})
}
return combine(converters)
}
/**
* Gets "convertPath" setting.
*
* 1. This checks `options` property, then returns it if exists.
* 2. This checks `settings.node` property, then returns it if exists.
* 3. This returns a function of identity.
*
* @param {RuleContext} context - The rule context.
* @returns {function} A function which converts a path.
*/
module.exports = function getConvertPath(context) {
return (
parse(context.options && context.options[0]) ||
parse(context.settings && context.settings.node) ||
identity
)
}
/**
* JSON Schema for `convertPath` option.
*/
module.exports.schema = {
anyOf: [
{
type: "object",
properties: {},
patternProperties: {
"^.+$": {
type: "array",
items: { type: "string" },
minItems: 2,
maxItems: 2,
},
},
additionalProperties: false,
},
{
type: "array",
items: {
type: "object",
properties: {
include: {
type: "array",
items: { type: "string" },
minItems: 1,
uniqueItems: true,
},
exclude: {
type: "array",
items: { type: "string" },
uniqueItems: true,
},
replace: {
type: "array",
items: { type: "string" },
minItems: 2,
maxItems: 2,
},
},
additionalProperties: false,
required: ["include", "replace"],
},
minItems: 1,
},
],
}
-184
View File
@@ -1,184 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const fs = require("fs")
const path = require("path")
const ignore = require("ignore")
const Cache = require("./cache")
const exists = require("./exists")
const getPackageJson = require("./get-package-json")
const cache = new Cache()
const SLASH_AT_BEGIN_AND_END = /^!?\/+|^!|\/+$/gu
const PARENT_RELATIVE_PATH = /^\.\./u
const NEVER_IGNORED = /^(?:readme\.[^.]*|(?:licen[cs]e|changes|changelog|history)(?:\.[^.]*)?)$/iu
/**
* Checks whether or not a given file name is a relative path to a ancestor
* directory.
*
* @param {string} filePath - A file name to check.
* @returns {boolean} `true` if the file name is a relative path to a ancestor
* directory.
*/
function isAncestorFiles(filePath) {
return PARENT_RELATIVE_PATH.test(filePath)
}
/**
* @param {function} f - A function.
* @param {function} g - A function.
* @returns {function} A logical-and function of `f` and `g`.
*/
function and(f, g) {
return filePath => f(filePath) && g(filePath)
}
/**
* @param {function} f - A function.
* @param {function} g - A function.
* @param {function|null} h - A function.
* @returns {function} A logical-or function of `f`, `g`, and `h`.
*/
function or(f, g, h) {
return filePath => f(filePath) || g(filePath) || (h && h(filePath))
}
/**
* @param {function} f - A function.
* @returns {function} A logical-not function of `f`.
*/
function not(f) {
return filePath => !f(filePath)
}
/**
* Creates a function which checks whether or not a given file is ignoreable.
*
* @param {object} p - An object of package.json.
* @returns {function} A function which checks whether or not a given file is ignoreable.
*/
function filterNeverIgnoredFiles(p) {
const basedir = path.dirname(p.filePath)
const mainFilePath =
typeof p.main === "string" ? path.join(basedir, p.main) : null
return filePath =>
path.join(basedir, filePath) !== mainFilePath &&
filePath !== "package.json" &&
!NEVER_IGNORED.test(path.relative(basedir, filePath))
}
/**
* Creates a function which checks whether or not a given file should be ignored.
*
* @param {string[]|null} files - File names of whitelist.
* @returns {function|null} A function which checks whether or not a given file should be ignored.
*/
function parseWhiteList(files) {
if (!files || !Array.isArray(files)) {
return null
}
const ig = ignore()
const igN = ignore()
let hasN = false
for (const file of files) {
if (typeof file === "string" && file) {
const body = file.replace(SLASH_AT_BEGIN_AND_END, "")
if (file.startsWith("!")) {
igN.add(`${body}`)
igN.add(`${body}/**`)
hasN = true
} else {
ig.add(`/${body}`)
ig.add(`/${body}/**`)
}
}
}
return hasN
? or(ig.createFilter(), not(igN.createFilter()))
: ig.createFilter()
}
/**
* Creates a function which checks whether or not a given file should be ignored.
*
* @param {string} basedir - The directory path "package.json" exists.
* @param {boolean} filesFieldExists - `true` if `files` field of `package.json` exists.
* @returns {function|null} A function which checks whether or not a given file should be ignored.
*/
function parseNpmignore(basedir, filesFieldExists) {
let filePath = path.join(basedir, ".npmignore")
if (!exists(filePath)) {
if (filesFieldExists) {
return null
}
filePath = path.join(basedir, ".gitignore")
if (!exists(filePath)) {
return null
}
}
const ig = ignore()
ig.add(fs.readFileSync(filePath, "utf8"))
return not(ig.createFilter())
}
/**
* Gets an object to check whether a given path should be ignored or not.
* The object is created from:
*
* - `files` field of `package.json`
* - `.npmignore`
*
* @param {string} startPath - A file path to lookup.
* @returns {object}
* An object to check whther or not a given path should be ignored.
* The object has a method `match`.
* `match` returns `true` if a given file path should be ignored.
*/
module.exports = function getNpmignore(startPath) {
const retv = { match: isAncestorFiles }
const p = getPackageJson(startPath)
if (p) {
const data = cache.get(p.filePath)
if (data) {
return data
}
const filesIgnore = parseWhiteList(p.files)
const npmignoreIgnore = parseNpmignore(
path.dirname(p.filePath),
Boolean(filesIgnore)
)
if (filesIgnore && npmignoreIgnore) {
retv.match = and(
filterNeverIgnoredFiles(p),
or(isAncestorFiles, filesIgnore, npmignoreIgnore)
)
} else if (filesIgnore) {
retv.match = and(
filterNeverIgnoredFiles(p),
or(isAncestorFiles, filesIgnore)
)
} else if (npmignoreIgnore) {
retv.match = and(
filterNeverIgnoredFiles(p),
or(isAncestorFiles, npmignoreIgnore)
)
}
cache.set(p.filePath, retv)
}
return retv
}
-75
View File
@@ -1,75 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const fs = require("fs")
const path = require("path")
const Cache = require("./cache")
const cache = new Cache()
/**
* Reads the `package.json` data in a given path.
*
* Don't cache the data.
*
* @param {string} dir - The path to a directory to read.
* @returns {object|null} The read `package.json` data, or null.
*/
function readPackageJson(dir) {
const filePath = path.join(dir, "package.json")
try {
const text = fs.readFileSync(filePath, "utf8")
const data = JSON.parse(text)
if (typeof data === "object" && data !== null) {
data.filePath = filePath
return data
}
} catch (_err) {
// do nothing.
}
return null
}
/**
* Gets a `package.json` data.
* The data is cached if found, then it's used after.
*
* @param {string} [startPath] - A file path to lookup.
* @returns {object|null} A found `package.json` data or `null`.
* This object have additional property `filePath`.
*/
module.exports = function getPackageJson(startPath = "a.js") {
const startDir = path.dirname(path.resolve(startPath))
let dir = startDir
let prevDir = ""
let data = null
do {
data = cache.get(dir)
if (data) {
if (dir !== startDir) {
cache.set(startDir, data)
}
return data
}
data = readPackageJson(dir)
if (data) {
cache.set(dir, data)
cache.set(startDir, data)
return data
}
// Go to next.
prevDir = dir
dir = path.resolve(dir, "..")
} while (dir !== prevDir)
cache.set(startDir, null)
return null
}
-44
View File
@@ -1,44 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const DEFAULT_VALUE = Object.freeze([])
/**
* Gets `resolvePaths` property from a given option object.
*
* @param {object|undefined} option - An option object to get.
* @returns {string[]|null} The `allowModules` value, or `null`.
*/
function get(option) {
if (option && option.resolvePaths && Array.isArray(option.resolvePaths)) {
return option.resolvePaths.map(String)
}
return null
}
/**
* Gets "resolvePaths" setting.
*
* 1. This checks `options` property, then returns it if exists.
* 2. This checks `settings.node` property, then returns it if exists.
* 3. This returns `[]`.
*
* @param {RuleContext} context - The rule context.
* @returns {string[]} A list of extensions.
*/
module.exports = function getResolvePaths(context, optionIndex = 0) {
return (
get(context.options && context.options[optionIndex]) ||
get(context.settings && context.settings.node) ||
DEFAULT_VALUE
)
}
module.exports.schema = {
type: "array",
items: { type: "string" },
uniqueItems: true,
}
-30
View File
@@ -1,30 +0,0 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
const { Range } = require("semver")
const cache = new Map()
/**
* Get the `semver.Range` object of a given range text.
* @param {string} x The text expression for a semver range.
* @returns {Range|null} The range object of a given range text.
* It's null if the `x` is not a valid range text.
*/
module.exports = function getSemverRange(x) {
const s = String(x)
let ret = cache.get(s) || null
if (!ret) {
try {
ret = new Range(s)
} catch (_error) {
// Ignore parsing error.
}
cache.set(s, ret)
}
return ret
}
-47
View File
@@ -1,47 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const DEFAULT_VALUE = Object.freeze([".js", ".json", ".node"])
/**
* Gets `tryExtensions` property from a given option object.
*
* @param {object|undefined} option - An option object to get.
* @returns {string[]|null} The `tryExtensions` value, or `null`.
*/
function get(option) {
if (option && option.tryExtensions && Array.isArray(option.tryExtensions)) {
return option.tryExtensions.map(String)
}
return null
}
/**
* Gets "tryExtensions" setting.
*
* 1. This checks `options` property, then returns it if exists.
* 2. This checks `settings.node` property, then returns it if exists.
* 3. This returns `[".js", ".json", ".node"]`.
*
* @param {RuleContext} context - The rule context.
* @returns {string[]} A list of extensions.
*/
module.exports = function getTryExtensions(context, optionIndex = 0) {
return (
get(context.options && context.options[optionIndex]) ||
get(context.settings && context.settings.node) ||
DEFAULT_VALUE
)
}
module.exports.schema = {
type: "array",
items: {
type: "string",
pattern: "^\\.",
},
uniqueItems: true,
}
-85
View File
@@ -1,85 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const resolve = require("resolve")
/**
* Resolve the given id to file paths.
* @param {boolean} isModule The flag which indicates this id is a module.
* @param {string} id The id to resolve.
* @param {object} options The options of node-resolve module.
* It requires `options.basedir`.
* @returns {string|null} The resolved path.
*/
function getFilePath(isModule, id, options) {
try {
return resolve.sync(id, options)
} catch (_err) {
if (isModule) {
return null
}
return path.resolve(options.basedir, id)
}
}
/**
* Gets the module name of a given path.
*
* e.g. `eslint/lib/ast-utils` -> `eslint`
*
* @param {string} nameOrPath - A path to get.
* @returns {string} The module name of the path.
*/
function getModuleName(nameOrPath) {
let end = nameOrPath.indexOf("/")
if (end !== -1 && nameOrPath[0] === "@") {
end = nameOrPath.indexOf("/", 1 + end)
}
return end === -1 ? nameOrPath : nameOrPath.slice(0, end)
}
/**
* Information of an import target.
*/
module.exports = class ImportTarget {
/**
* Initialize this instance.
* @param {ASTNode} node - The node of a `require()` or a module declaraiton.
* @param {string} name - The name of an import target.
* @param {object} options - The options of `node-resolve` module.
*/
constructor(node, name, options) {
const isModule = !/^(?:[./\\]|\w+:)/u.test(name)
/**
* The node of a `require()` or a module declaraiton.
* @type {ASTNode}
*/
this.node = node
/**
* The name of this import target.
* @type {string}
*/
this.name = name
/**
* The full path of this import target.
* If the target is a module and it does not exist then this is `null`.
* @type {string|null}
*/
this.filePath = getFilePath(isModule, name, options)
/**
* The module name of this import target.
* If the target is a relative path then this is `null`.
* @type {string|null}
*/
this.moduleName = isModule ? getModuleName(name) : null
}
}
-46
View File
@@ -1,46 +0,0 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
/**
* Merge two visitors.
* This function modifies `visitor1` directly to merge.
* @param {Visitor} visitor1 The visitor which is assigned.
* @param {Visitor} visitor2 The visitor which is assigning.
* @returns {Visitor} `visitor1`.
*/
module.exports = function mergeVisitorsInPlace(visitor1, visitor2) {
for (const key of Object.keys(visitor2)) {
const handler1 = visitor1[key]
const handler2 = visitor2[key]
if (typeof handler1 === "function") {
if (handler1._handlers) {
handler1._handlers.push(handler2)
} else {
const handlers = [handler1, handler2]
visitor1[key] = Object.assign(dispatch.bind(null, handlers), {
_handlers: handlers,
})
}
} else {
visitor1[key] = handler2
}
}
return visitor1
}
/**
* Dispatch all given functions with a node.
* @param {function[]} handlers The function list to call.
* @param {Node} node The AST node to be handled.
* @returns {void}
*/
function dispatch(handlers, node) {
for (const h of handlers) {
h(node)
}
}
-10
View File
@@ -1,10 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = function stripImportPathParams(path) {
const i = path.indexOf("!")
return i === -1 ? path : path.slice(0, i)
}
-65
View File
@@ -1,65 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const resolve = require("resolve")
const getResolvePaths = require("./get-resolve-paths")
const getTryExtensions = require("./get-try-extensions")
const ImportTarget = require("./import-target")
const stripImportPathParams = require("./strip-import-path-params")
/**
* Gets a list of `import`/`export` declaration targets.
*
* Core modules of Node.js (e.g. `fs`, `http`) are excluded.
*
* @param {RuleContext} context - The rule context.
* @param {Object} [options] - The flag to include core modules.
* @param {boolean} [options.includeCore] - The flag to include core modules.
* @param {number} [options.optionIndex] - The index of rule options.
* @param {function(ImportTarget[]):void} callback The callback function to get result.
* @returns {ImportTarget[]} A list of found target's information.
*/
module.exports = function visitImport(
context,
{ includeCore = false, optionIndex = 0 } = {},
callback
) {
const targets = []
const basedir = path.dirname(path.resolve(context.getFilename()))
const paths = getResolvePaths(context, optionIndex)
const extensions = getTryExtensions(context, optionIndex)
const options = { basedir, paths, extensions }
return {
[[
"ExportAllDeclaration",
"ExportNamedDeclaration",
"ImportDeclaration",
"ImportExpression",
]](node) {
const sourceNode = node.source
// skip `import(foo)`
if (
node.type === "ImportExpression" &&
sourceNode &&
sourceNode.type !== "Literal"
) {
return
}
const name = sourceNode && stripImportPathParams(sourceNode.value)
if (name && (includeCore || !resolve.isCore(name))) {
targets.push(new ImportTarget(sourceNode, name, options))
}
},
"Program:exit"() {
callback(targets)
},
}
}
-59
View File
@@ -1,59 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const { CALL, ReferenceTracker, getStringIfConstant } = require("eslint-utils")
const resolve = require("resolve")
const getResolvePaths = require("./get-resolve-paths")
const getTryExtensions = require("./get-try-extensions")
const ImportTarget = require("./import-target")
const stripImportPathParams = require("./strip-import-path-params")
/**
* Gets a list of `require()` targets.
*
* Core modules of Node.js (e.g. `fs`, `http`) are excluded.
*
* @param {RuleContext} context - The rule context.
* @param {Object} [options] - The flag to include core modules.
* @param {boolean} [options.includeCore] - The flag to include core modules.
* @param {function(ImportTarget[]):void} callback The callback function to get result.
* @returns {Object} The visitor.
*/
module.exports = function visitRequire(
context,
{ includeCore = false } = {},
callback
) {
const targets = []
const basedir = path.dirname(path.resolve(context.getFilename()))
const paths = getResolvePaths(context)
const extensions = getTryExtensions(context)
const options = { basedir, paths, extensions }
return {
"Program:exit"() {
const tracker = new ReferenceTracker(context.getScope())
const references = tracker.iterateGlobalReferences({
require: {
[CALL]: true,
resolve: { [CALL]: true },
},
})
for (const { node } of references) {
const targetNode = node.arguments[0]
const rawName = getStringIfConstant(targetNode)
const name = rawName && stripImportPathParams(rawName)
if (name && (includeCore || !resolve.isCore(name))) {
targets.push(new ImportTarget(targetNode, name, options))
}
}
callback(targets)
},
}
}