拿掉 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
-22
View File
@@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Toru Nagashima
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-176
View File
@@ -1,176 +0,0 @@
# eslint-plugin-node
[![npm version](https://img.shields.io/npm/v/eslint-plugin-node.svg)](https://www.npmjs.com/package/eslint-plugin-node)
[![Downloads/month](https://img.shields.io/npm/dm/eslint-plugin-node.svg)](http://www.npmtrends.com/eslint-plugin-node)
[![Build Status](https://github.com/mysticatea/eslint-plugin-node/workflows/CI/badge.svg)](https://github.com/mysticatea/eslint-plugin-node/actions)
[![Coverage Status](https://codecov.io/gh/mysticatea/eslint-plugin-node/branch/master/graph/badge.svg)](https://codecov.io/gh/mysticatea/eslint-plugin-node)
[![Dependency Status](https://david-dm.org/mysticatea/eslint-plugin-node.svg)](https://david-dm.org/mysticatea/eslint-plugin-node)
Additional ESLint's rules for Node.js
## 💿 Install & Usage
```
$ npm install --save-dev eslint eslint-plugin-node
```
- Requires Node.js `>=8.10.0`
- Requires ESLint `>=5.16.0`
**Note:** It recommends a use of [the "engines" field of package.json](https://docs.npmjs.com/files/package.json#engines). The "engines" field is used by `node/no-unsupported-features/*` rules.
**.eslintrc.json** (An example)
```jsonc
{
"extends": [
"eslint:recommended",
"plugin:node/recommended"
],
"parserOptions": {
// Only ESLint 6.2.0 and later support ES2020.
"ecmaVersion": 2020
},
"rules": {
"node/exports-style": ["error", "module.exports"],
"node/file-extension-in-import": ["error", "always"],
"node/prefer-global/buffer": ["error", "always"],
"node/prefer-global/console": ["error", "always"],
"node/prefer-global/process": ["error", "always"],
"node/prefer-global/url-search-params": ["error", "always"],
"node/prefer-global/url": ["error", "always"],
"node/prefer-promises/dns": "error",
"node/prefer-promises/fs": "error"
}
}
```
**package.json** (An example)
```json
{
"name": "your-module",
"version": "1.0.0",
"type": "commonjs",
"engines": {
"node": ">=8.10.0"
}
}
```
## 📖 Rules
- ⭐️ - the mark of recommended rules.
- ✒️ - the mark of fixable rules.
<!--RULES_TABLE_START-->
### Possible Errors
| Rule ID | Description | |
|:--------|:------------|:--:|
| [node/no-callback-literal](./docs/rules/no-callback-literal.md) | ensure Node.js-style error-first callback pattern is followed | |
| [node/no-exports-assign](./docs/rules/no-exports-assign.md) | disallow the assignment to `exports` | ⭐️ |
| [node/no-extraneous-import](./docs/rules/no-extraneous-import.md) | disallow `import` declarations which import extraneous modules | ⭐️ |
| [node/no-extraneous-require](./docs/rules/no-extraneous-require.md) | disallow `require()` expressions which import extraneous modules | ⭐️ |
| [node/no-missing-import](./docs/rules/no-missing-import.md) | disallow `import` declarations which import non-existence modules | ⭐️ |
| [node/no-missing-require](./docs/rules/no-missing-require.md) | disallow `require()` expressions which import non-existence modules | ⭐️ |
| [node/no-unpublished-bin](./docs/rules/no-unpublished-bin.md) | disallow `bin` files that npm ignores | ⭐️ |
| [node/no-unpublished-import](./docs/rules/no-unpublished-import.md) | disallow `import` declarations which import private modules | ⭐️ |
| [node/no-unpublished-require](./docs/rules/no-unpublished-require.md) | disallow `require()` expressions which import private modules | ⭐️ |
| [node/no-unsupported-features/es-builtins](./docs/rules/no-unsupported-features/es-builtins.md) | disallow unsupported ECMAScript built-ins on the specified version | ⭐️ |
| [node/no-unsupported-features/es-syntax](./docs/rules/no-unsupported-features/es-syntax.md) | disallow unsupported ECMAScript syntax on the specified version | ⭐️ |
| [node/no-unsupported-features/node-builtins](./docs/rules/no-unsupported-features/node-builtins.md) | disallow unsupported Node.js built-in APIs on the specified version | ⭐️ |
| [node/process-exit-as-throw](./docs/rules/process-exit-as-throw.md) | make `process.exit()` expressions the same code path as `throw` | ⭐️ |
| [node/shebang](./docs/rules/shebang.md) | suggest correct usage of shebang | ⭐️✒️ |
### Best Practices
| Rule ID | Description | |
|:--------|:------------|:--:|
| [node/no-deprecated-api](./docs/rules/no-deprecated-api.md) | disallow deprecated APIs | ⭐️ |
### Stylistic Issues
| Rule ID | Description | |
|:--------|:------------|:--:|
| [node/exports-style](./docs/rules/exports-style.md) | enforce either `module.exports` or `exports` | |
| [node/file-extension-in-import](./docs/rules/file-extension-in-import.md) | enforce the style of file extensions in `import` declarations | ✒️ |
| [node/prefer-global/buffer](./docs/rules/prefer-global/buffer.md) | enforce either `Buffer` or `require("buffer").Buffer` | |
| [node/prefer-global/console](./docs/rules/prefer-global/console.md) | enforce either `console` or `require("console")` | |
| [node/prefer-global/process](./docs/rules/prefer-global/process.md) | enforce either `process` or `require("process")` | |
| [node/prefer-global/text-decoder](./docs/rules/prefer-global/text-decoder.md) | enforce either `TextDecoder` or `require("util").TextDecoder` | |
| [node/prefer-global/text-encoder](./docs/rules/prefer-global/text-encoder.md) | enforce either `TextEncoder` or `require("util").TextEncoder` | |
| [node/prefer-global/url-search-params](./docs/rules/prefer-global/url-search-params.md) | enforce either `URLSearchParams` or `require("url").URLSearchParams` | |
| [node/prefer-global/url](./docs/rules/prefer-global/url.md) | enforce either `URL` or `require("url").URL` | |
| [node/prefer-promises/dns](./docs/rules/prefer-promises/dns.md) | enforce `require("dns").promises` | |
| [node/prefer-promises/fs](./docs/rules/prefer-promises/fs.md) | enforce `require("fs").promises` | |
### Deprecated rules
These rules have been deprecated in accordance with the [deprecation policy](https://eslint.org/docs/user-guide/rule-deprecation), and replaced by newer rules:
| Rule ID | Replaced by |
|:--------|:------------|
| [node/no-hide-core-modules](./docs/rules/no-hide-core-modules.md) | (nothing) |
| [node/no-unsupported-features](./docs/rules/no-unsupported-features.md) | [node/no-unsupported-features/es-syntax](./docs/rules/no-unsupported-features/es-syntax.md) and [node/no-unsupported-features/es-builtins](./docs/rules/no-unsupported-features/es-builtins.md) |
<!--RULES_TABLE_END-->
## 🔧 Configs
This plugin provides three configs:
- `plugin:node/recommended` condiders both CommonJS and ES Modules. If [`"type":"module"` field](https://medium.com/@nodejs/announcing-a-new-experimental-modules-1be8d2d6c2ff#b023) existed in package.json then it considers files as ES Modules. Otherwise it considers files as CommonJS. In addition, it considers `*.mjs` files as ES Modules and `*.cjs` files as CommonJS.
- `plugin:node/recommended-module` considers all files as ES Modules.
- `plugin:node/recommended-script` considers all files as CommonJS.
Those preset config:
- enable [no-process-exit](http://eslint.org/docs/rules/no-process-exit) rule because [the official document](https://nodejs.org/api/process.html#process_process_exit_code) does not recommend a use of `process.exit()`.
- enable plugin rules which are given :star: in the above table.
- add `{ecmaVersion: 2019}` and etc into `parserOptions`.
- add proper globals into `globals`.
- add this plugin into `plugins`.
## 👫 FAQ
- Q: The `no-missing-import` / `no-missing-require` rules don't work with nested folders in SublimeLinter-eslint
- A: See [context.getFilename() in rule returns relative path](https://github.com/roadhump/SublimeLinter-eslint#contextgetfilename-in-rule-returns-relative-path) in the SublimeLinter-eslint FAQ.
## 🚥 Semantic Versioning Policy
`eslint-plugin-node` follows [semantic versioning](http://semver.org/) and [ESLint's Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy).
- Patch release (intended to not break your lint build)
- A bug fix in a rule that results in it reporting fewer errors.
- Improvements to documentation.
- Non-user-facing changes such as refactoring code, adding, deleting, or modifying tests, and increasing test coverage.
- Re-releasing after a failed release (i.e., publishing a release that doesn't work for anyone).
- Minor release (might break your lint build)
- A bug fix in a rule that results in it reporting more errors.
- A new rule is created.
- A new option to an existing rule is created.
- An existing rule is deprecated.
- Major release (likely to break your lint build)
- A support for old Node version is dropped.
- A support for old ESLint version is dropped.
- An existing rule is changed in it reporting more errors.
- An existing rule is removed.
- An existing option of a rule is removed.
- An existing config is updated.
## 📰 Changelog
- [GitHub Releases](https://github.com/mysticatea/eslint-plugin-node/releases)
## ❤️ Contributing
Welcome contributing!
Please use GitHub's Issues/PRs.
### Development Tools
- `npm test` runs tests and measures coverage.
- `npm run coverage` shows the coverage result of `npm test` command.
- `npm run clean` removes the coverage result of `npm test` command.
-76
View File
@@ -1,76 +0,0 @@
"use strict"
module.exports = {
commonGlobals: {
// ECMAScript
ArrayBuffer: "readonly",
Atomics: "readonly",
BigInt: "readonly",
BigInt64Array: "readonly",
BigUint64Array: "readonly",
DataView: "readonly",
Float32Array: "readonly",
Float64Array: "readonly",
Int16Array: "readonly",
Int32Array: "readonly",
Int8Array: "readonly",
Map: "readonly",
Promise: "readonly",
Proxy: "readonly",
Reflect: "readonly",
Set: "readonly",
SharedArrayBuffer: "readonly",
Symbol: "readonly",
Uint16Array: "readonly",
Uint32Array: "readonly",
Uint8Array: "readonly",
Uint8ClampedArray: "readonly",
WeakMap: "readonly",
WeakSet: "readonly",
// ECMAScript (experimental)
globalThis: "readonly",
// ECMA-404
Intl: "readonly",
// Web Standard
TextDecoder: "readonly",
TextEncoder: "readonly",
URL: "readonly",
URLSearchParams: "readonly",
WebAssembly: "readonly",
clearInterval: "readonly",
clearTimeout: "readonly",
console: "readonly",
queueMicrotask: "readonly",
setInterval: "readonly",
setTimeout: "readonly",
// Node.js
Buffer: "readonly",
GLOBAL: "readonly",
clearImmediate: "readonly",
global: "readonly",
process: "readonly",
root: "readonly",
setImmediate: "readonly",
},
commonRules: {
"no-process-exit": "error",
"node/no-deprecated-api": "error",
"node/no-extraneous-import": "error",
"node/no-extraneous-require": "error",
"node/no-exports-assign": "error",
"node/no-missing-import": "error",
"node/no-missing-require": "error",
"node/no-unpublished-bin": "error",
"node/no-unpublished-import": "error",
"node/no-unpublished-require": "error",
"node/no-unsupported-features/es-builtins": "error",
"node/no-unsupported-features/es-syntax": "error",
"node/no-unsupported-features/node-builtins": "error",
"node/process-exit-as-throw": "error",
"node/shebang": "error",
},
}
-27
View File
@@ -1,27 +0,0 @@
"use strict"
const { commonGlobals, commonRules } = require("./_commons")
module.exports = {
globals: {
...commonGlobals,
__dirname: "off",
__filename: "off",
exports: "off",
module: "off",
require: "off",
},
parserOptions: {
ecmaFeatures: { globalReturn: false },
ecmaVersion: 2019,
sourceType: "module",
},
plugins: ["node"],
rules: {
...commonRules,
"node/no-unsupported-features/es-syntax": [
"error",
{ ignores: ["modules"] },
],
},
}
-24
View File
@@ -1,24 +0,0 @@
"use strict"
const { commonGlobals, commonRules } = require("./_commons")
module.exports = {
globals: {
...commonGlobals,
__dirname: "readonly",
__filename: "readonly",
exports: "writable",
module: "readonly",
require: "readonly",
},
parserOptions: {
ecmaFeatures: { globalReturn: true },
ecmaVersion: 2019,
sourceType: "script",
},
plugins: ["node"],
rules: {
...commonRules,
"node/no-unsupported-features/es-syntax": ["error", { ignores: [] }],
},
}
-18
View File
@@ -1,18 +0,0 @@
"use strict"
const getPackageJson = require("../util/get-package-json")
const moduleConfig = require("./recommended-module")
const scriptConfig = require("./recommended-script")
module.exports = () => {
const packageJson = getPackageJson()
const isModule = (packageJson && packageJson.type) === "module"
return {
...(isModule ? moduleConfig : scriptConfig),
overrides: [
{ files: ["*.cjs", ".*.cjs"], ...scriptConfig },
{ files: ["*.mjs", ".*.mjs"], ...moduleConfig },
],
}
}
-55
View File
@@ -1,55 +0,0 @@
/* DON'T EDIT THIS FILE. This is generated by 'scripts/update-lib-index.js' */
"use strict"
module.exports = {
configs: {
"recommended-module": require("./configs/recommended-module"),
"recommended-script": require("./configs/recommended-script"),
get recommended() {
return require("./configs/recommended")()
},
},
rules: {
"callback-return": require("./rules/callback-return"),
"exports-style": require("./rules/exports-style"),
"file-extension-in-import": require("./rules/file-extension-in-import"),
"global-require": require("./rules/global-require"),
"handle-callback-err": require("./rules/handle-callback-err"),
"no-callback-literal": require("./rules/no-callback-literal"),
"no-deprecated-api": require("./rules/no-deprecated-api"),
"no-exports-assign": require("./rules/no-exports-assign"),
"no-extraneous-import": require("./rules/no-extraneous-import"),
"no-extraneous-require": require("./rules/no-extraneous-require"),
"no-missing-import": require("./rules/no-missing-import"),
"no-missing-require": require("./rules/no-missing-require"),
"no-mixed-requires": require("./rules/no-mixed-requires"),
"no-new-require": require("./rules/no-new-require"),
"no-path-concat": require("./rules/no-path-concat"),
"no-process-env": require("./rules/no-process-env"),
"no-process-exit": require("./rules/no-process-exit"),
"no-restricted-import": require("./rules/no-restricted-import"),
"no-restricted-require": require("./rules/no-restricted-require"),
"no-sync": require("./rules/no-sync"),
"no-unpublished-bin": require("./rules/no-unpublished-bin"),
"no-unpublished-import": require("./rules/no-unpublished-import"),
"no-unpublished-require": require("./rules/no-unpublished-require"),
"no-unsupported-features/es-builtins": require("./rules/no-unsupported-features/es-builtins"),
"no-unsupported-features/es-syntax": require("./rules/no-unsupported-features/es-syntax"),
"no-unsupported-features/node-builtins": require("./rules/no-unsupported-features/node-builtins"),
"prefer-global/buffer": require("./rules/prefer-global/buffer"),
"prefer-global/console": require("./rules/prefer-global/console"),
"prefer-global/process": require("./rules/prefer-global/process"),
"prefer-global/text-decoder": require("./rules/prefer-global/text-decoder"),
"prefer-global/text-encoder": require("./rules/prefer-global/text-encoder"),
"prefer-global/url-search-params": require("./rules/prefer-global/url-search-params"),
"prefer-global/url": require("./rules/prefer-global/url"),
"prefer-promises/dns": require("./rules/prefer-promises/dns"),
"prefer-promises/fs": require("./rules/prefer-promises/fs"),
"process-exit-as-throw": require("./rules/process-exit-as-throw"),
shebang: require("./rules/shebang"),
// Deprecated rules.
"no-hide-core-modules": require("./rules/no-hide-core-modules"),
"no-unsupported-features": require("./rules/no-unsupported-features"),
},
}
-185
View File
@@ -1,185 +0,0 @@
/**
* @author Jamund Ferguson
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "require `return` statements after callbacks",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md",
},
schema: [
{
type: "array",
items: { type: "string" },
},
],
fixable: null,
messages: {
missingReturn: "Expected return with your callback function.",
},
},
create(context) {
const callbacks = context.options[0] || ["callback", "cb", "next"]
const sourceCode = context.getSourceCode()
/**
* Find the closest parent matching a list of types.
* @param {ASTNode} node The node whose parents we are searching
* @param {Array} types The node types to match
* @returns {ASTNode} The matched node or undefined.
*/
function findClosestParentOfType(node, types) {
if (!node.parent) {
return null
}
if (types.indexOf(node.parent.type) === -1) {
return findClosestParentOfType(node.parent, types)
}
return node.parent
}
/**
* Check to see if a node contains only identifers
* @param {ASTNode} node The node to check
* @returns {boolean} Whether or not the node contains only identifers
*/
function containsOnlyIdentifiers(node) {
if (node.type === "Identifier") {
return true
}
if (node.type === "MemberExpression") {
if (node.object.type === "Identifier") {
return true
}
if (node.object.type === "MemberExpression") {
return containsOnlyIdentifiers(node.object)
}
}
return false
}
/**
* Check to see if a CallExpression is in our callback list.
* @param {ASTNode} node The node to check against our callback names list.
* @returns {boolean} Whether or not this function matches our callback name.
*/
function isCallback(node) {
return (
containsOnlyIdentifiers(node.callee) &&
callbacks.indexOf(sourceCode.getText(node.callee)) > -1
)
}
/**
* Determines whether or not the callback is part of a callback expression.
* @param {ASTNode} node The callback node
* @param {ASTNode} parentNode The expression node
* @returns {boolean} Whether or not this is part of a callback expression
*/
function isCallbackExpression(node, parentNode) {
// ensure the parent node exists and is an expression
if (!parentNode || parentNode.type !== "ExpressionStatement") {
return false
}
// cb()
if (parentNode.expression === node) {
return true
}
// special case for cb && cb() and similar
if (
parentNode.expression.type === "BinaryExpression" ||
parentNode.expression.type === "LogicalExpression"
) {
if (parentNode.expression.right === node) {
return true
}
}
return false
}
return {
CallExpression(node) {
// if we're not a callback we can return
if (!isCallback(node)) {
return
}
// find the closest block, return or loop
const closestBlock =
findClosestParentOfType(node, [
"BlockStatement",
"ReturnStatement",
"ArrowFunctionExpression",
]) || {}
// if our parent is a return we know we're ok
if (closestBlock.type === "ReturnStatement") {
return
}
// arrow functions don't always have blocks and implicitly return
if (closestBlock.type === "ArrowFunctionExpression") {
return
}
// block statements are part of functions and most if statements
if (closestBlock.type === "BlockStatement") {
// find the last item in the block
const lastItem =
closestBlock.body[closestBlock.body.length - 1]
// if the callback is the last thing in a block that might be ok
if (isCallbackExpression(node, lastItem)) {
const parentType = closestBlock.parent.type
// but only if the block is part of a function
if (
parentType === "FunctionExpression" ||
parentType === "FunctionDeclaration" ||
parentType === "ArrowFunctionExpression"
) {
return
}
}
// ending a block with a return is also ok
if (lastItem.type === "ReturnStatement") {
// but only if the callback is immediately before
if (
isCallbackExpression(
node,
closestBlock.body[closestBlock.body.length - 2]
)
) {
return
}
}
}
// as long as you're the child of a function at this point you should be asked to return
if (
findClosestParentOfType(node, [
"FunctionDeclaration",
"FunctionExpression",
"ArrowFunctionExpression",
])
) {
context.report({ node, messageId: "missingReturn" })
}
},
}
},
}
-297
View File
@@ -1,297 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
/*istanbul ignore next */
/**
* This function is copied from https://github.com/eslint/eslint/blob/2355f8d0de1d6732605420d15ddd4f1eee3c37b6/lib/ast-utils.js#L648-L684
*
* @param {ASTNode} node - The node to get.
* @returns {string|null} The property name if static. Otherwise, null.
* @private
*/
function getStaticPropertyName(node) {
let prop = null
switch (node && node.type) {
case "Property":
case "MethodDefinition":
prop = node.key
break
case "MemberExpression":
prop = node.property
break
// no default
}
switch (prop && prop.type) {
case "Literal":
return String(prop.value)
case "TemplateLiteral":
if (prop.expressions.length === 0 && prop.quasis.length === 1) {
return prop.quasis[0].value.cooked
}
break
case "Identifier":
if (!node.computed) {
return prop.name
}
break
// no default
}
return null
}
/**
* Checks whether the given node is assignee or not.
*
* @param {ASTNode} node - The node to check.
* @returns {boolean} `true` if the node is assignee.
*/
function isAssignee(node) {
return (
node.parent.type === "AssignmentExpression" && node.parent.left === node
)
}
/**
* Gets the top assignment expression node if the given node is an assignee.
*
* This is used to distinguish 2 assignees belong to the same assignment.
* If the node is not an assignee, this returns null.
*
* @param {ASTNode} leafNode - The node to get.
* @returns {ASTNode|null} The top assignment expression node, or null.
*/
function getTopAssignment(leafNode) {
let node = leafNode
// Skip MemberExpressions.
while (
node.parent.type === "MemberExpression" &&
node.parent.object === node
) {
node = node.parent
}
// Check assignments.
if (!isAssignee(node)) {
return null
}
// Find the top.
while (node.parent.type === "AssignmentExpression") {
node = node.parent
}
return node
}
/**
* Gets top assignment nodes of the given node list.
*
* @param {ASTNode[]} nodes - The node list to get.
* @returns {ASTNode[]} Gotten top assignment nodes.
*/
function createAssignmentList(nodes) {
return nodes.map(getTopAssignment).filter(Boolean)
}
/**
* Gets the reference of `module.exports` from the given scope.
*
* @param {escope.Scope} scope - The scope to get.
* @returns {ASTNode[]} Gotten MemberExpression node list.
*/
function getModuleExportsNodes(scope) {
const variable = scope.set.get("module")
if (variable == null) {
return []
}
return variable.references
.map(reference => reference.identifier.parent)
.filter(
node =>
node.type === "MemberExpression" &&
getStaticPropertyName(node) === "exports"
)
}
/**
* Gets the reference of `exports` from the given scope.
*
* @param {escope.Scope} scope - The scope to get.
* @returns {ASTNode[]} Gotten Identifier node list.
*/
function getExportsNodes(scope) {
const variable = scope.set.get("exports")
if (variable == null) {
return []
}
return variable.references.map(reference => reference.identifier)
}
module.exports = {
meta: {
docs: {
description: "enforce either `module.exports` or `exports`",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/exports-style.md",
},
type: "suggestion",
fixable: null,
schema: [
{
//
enum: ["module.exports", "exports"],
},
{
type: "object",
properties: { allowBatchAssign: { type: "boolean" } },
additionalProperties: false,
},
],
},
create(context) {
const mode = context.options[0] || "module.exports"
const batchAssignAllowed = Boolean(
context.options[1] != null && context.options[1].allowBatchAssign
)
const sourceCode = context.getSourceCode()
/**
* Gets the location info of reports.
*
* exports = foo
* ^^^^^^^^^
*
* module.exports = foo
* ^^^^^^^^^^^^^^^^
*
* @param {ASTNode} node - The node of `exports`/`module.exports`.
* @returns {Location} The location info of reports.
*/
function getLocation(node) {
const token = sourceCode.getTokenAfter(node)
return {
start: node.loc.start,
end: token.loc.end,
}
}
/**
* Enforces `module.exports`.
* This warns references of `exports`.
*
* @returns {void}
*/
function enforceModuleExports() {
const globalScope = context.getScope()
const exportsNodes = getExportsNodes(globalScope)
const assignList = batchAssignAllowed
? createAssignmentList(getModuleExportsNodes(globalScope))
: []
for (const node of exportsNodes) {
// Skip if it's a batch assignment.
if (
assignList.length > 0 &&
assignList.indexOf(getTopAssignment(node)) !== -1
) {
continue
}
// Report.
context.report({
node,
loc: getLocation(node),
message:
"Unexpected access to 'exports'. Use 'module.exports' instead.",
})
}
}
/**
* Enforces `exports`.
* This warns references of `module.exports`.
*
* @returns {void}
*/
function enforceExports() {
const globalScope = context.getScope()
const exportsNodes = getExportsNodes(globalScope)
const moduleExportsNodes = getModuleExportsNodes(globalScope)
const assignList = batchAssignAllowed
? createAssignmentList(exportsNodes)
: []
const batchAssignList = []
for (const node of moduleExportsNodes) {
// Skip if it's a batch assignment.
if (assignList.length > 0) {
const found = assignList.indexOf(getTopAssignment(node))
if (found !== -1) {
batchAssignList.push(assignList[found])
assignList.splice(found, 1)
continue
}
}
// Report.
context.report({
node,
loc: getLocation(node),
message:
"Unexpected access to 'module.exports'. Use 'exports' instead.",
})
}
// Disallow direct assignment to `exports`.
for (const node of exportsNodes) {
// Skip if it's not assignee.
if (!isAssignee(node)) {
continue
}
// Check if it's a batch assignment.
if (batchAssignList.indexOf(getTopAssignment(node)) !== -1) {
continue
}
// Report.
context.report({
node,
loc: getLocation(node),
message:
"Unexpected assignment to 'exports'. Don't modify 'exports' itself.",
})
}
}
return {
"Program:exit"() {
switch (mode) {
case "module.exports":
enforceModuleExports()
break
case "exports":
enforceExports()
break
// no default
}
},
}
},
}
-129
View File
@@ -1,129 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const fs = require("fs")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")
const packageNamePattern = /^(?:@[^/\\]+[/\\])?[^/\\]+$/u
const corePackageOverridePattern = /^(?:assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|trace_events|tty|url|util|v8|vm|worker_threads|zlib)[/\\]$/u
/**
* Get all file extensions of the files which have the same basename.
* @param {string} filePath The path to the original file to check.
* @returns {string[]} File extensions.
*/
function getExistingExtensions(filePath) {
const basename = path.basename(filePath, path.extname(filePath))
try {
return fs
.readdirSync(path.dirname(filePath))
.filter(
filename =>
path.basename(filename, path.extname(filename)) === basename
)
.map(filename => path.extname(filename))
} catch (_error) {
return []
}
}
module.exports = {
meta: {
docs: {
description:
"enforce the style of file extensions in `import` declarations",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/file-extension-in-import.md",
},
fixable: "code",
messages: {
requireExt: "require file extension '{{ext}}'.",
forbidExt: "forbid file extension '{{ext}}'.",
},
schema: [
{
enum: ["always", "never"],
},
{
type: "object",
properties: {
tryExtensions: getTryExtensions.schema,
},
additionalProperties: {
enum: ["always", "never"],
},
},
],
type: "suggestion",
},
create(context) {
if (context.getFilename().startsWith("<")) {
return {}
}
const defaultStyle = context.options[0] || "always"
const overrideStyle = context.options[1] || {}
function verify({ filePath, name, node }) {
// Ignore if it's not resolved to a file or it's a bare module.
if (
!filePath ||
packageNamePattern.test(name) ||
corePackageOverridePattern.test(name)
) {
return
}
// Get extension.
const originalExt = path.extname(name)
const resolvedExt = path.extname(filePath)
const existingExts = getExistingExtensions(filePath)
if (!resolvedExt && existingExts.length !== 1) {
// Ignore if the file extension could not be determined one.
return
}
const ext = resolvedExt || existingExts[0]
const style = overrideStyle[ext] || defaultStyle
// Verify.
if (style === "always" && ext !== originalExt) {
context.report({
node,
messageId: "requireExt",
data: { ext },
fix(fixer) {
if (existingExts.length !== 1) {
return null
}
const index = node.range[1] - 1
return fixer.insertTextBeforeRange([index, index], ext)
},
})
} else if (style === "never" && ext === originalExt) {
context.report({
node,
messageId: "forbidExt",
data: { ext },
fix(fixer) {
if (existingExts.length !== 1) {
return null
}
const index = name.lastIndexOf(ext)
const start = node.range[0] + 1 + index
const end = start + ext.length
return fixer.removeRange([start, end])
},
})
}
}
return visitImport(context, { optionIndex: 1 }, targets => {
targets.forEach(verify)
})
},
}
-91
View File
@@ -1,91 +0,0 @@
/**
* @author Jamund Ferguson
* See LICENSE file in root directory for full license.
*/
"use strict"
const ACCEPTABLE_PARENTS = [
"AssignmentExpression",
"VariableDeclarator",
"MemberExpression",
"ExpressionStatement",
"CallExpression",
"ConditionalExpression",
"Program",
"VariableDeclaration",
]
/**
* Finds the eslint-scope reference in the given scope.
* @param {Object} scope The scope to search.
* @param {ASTNode} node The identifier node.
* @returns {Reference|null} Returns the found reference or null if none were found.
*/
function findReference(scope, node) {
const references = scope.references.filter(
reference =>
reference.identifier.range[0] === node.range[0] &&
reference.identifier.range[1] === node.range[1]
)
/* istanbul ignore else: correctly returns null */
if (references.length === 1) {
return references[0]
}
return null
}
/**
* Checks if the given identifier node is shadowed in the given scope.
* @param {Object} scope The current scope.
* @param {ASTNode} node The identifier node to check.
* @returns {boolean} Whether or not the name is shadowed.
*/
function isShadowed(scope, node) {
const reference = findReference(scope, node)
return reference && reference.resolved && reference.resolved.defs.length > 0
}
module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"require `require()` calls to be placed at top-level module scope",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/global-require.md",
},
fixable: null,
schema: [],
messages: {
unexpected: "Unexpected require().",
},
},
create(context) {
return {
CallExpression(node) {
const currentScope = context.getScope()
if (
node.callee.name === "require" &&
!isShadowed(currentScope, node.callee)
) {
const isGoodRequire = context
.getAncestors()
.every(
parent =>
ACCEPTABLE_PARENTS.indexOf(parent.type) > -1
)
if (!isGoodRequire) {
context.report({ node, messageId: "unexpected" })
}
}
},
}
},
}
-94
View File
@@ -1,94 +0,0 @@
/**
* @author Jamund Ferguson
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "require error handling in callbacks",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/handle-callback-err.md",
},
fixable: null,
schema: [
{
type: "string",
},
],
messages: {
expected: "Expected error to be handled.",
},
},
create(context) {
const errorArgument = context.options[0] || "err"
/**
* Checks if the given argument should be interpreted as a regexp pattern.
* @param {string} stringToCheck The string which should be checked.
* @returns {boolean} Whether or not the string should be interpreted as a pattern.
*/
function isPattern(stringToCheck) {
const firstChar = stringToCheck[0]
return firstChar === "^"
}
/**
* Checks if the given name matches the configured error argument.
* @param {string} name The name which should be compared.
* @returns {boolean} Whether or not the given name matches the configured error variable name.
*/
function matchesConfiguredErrorName(name) {
if (isPattern(errorArgument)) {
const regexp = new RegExp(errorArgument, "u")
return regexp.test(name)
}
return name === errorArgument
}
/**
* Get the parameters of a given function scope.
* @param {Object} scope The function scope.
* @returns {Array} All parameters of the given scope.
*/
function getParameters(scope) {
return scope.variables.filter(
variable =>
variable.defs[0] && variable.defs[0].type === "Parameter"
)
}
/**
* Check to see if we're handling the error object properly.
* @param {ASTNode} node The AST node to check.
* @returns {void}
*/
function checkForError(node) {
const scope = context.getScope()
const parameters = getParameters(scope)
const firstParameter = parameters[0]
if (
firstParameter &&
matchesConfiguredErrorName(firstParameter.name)
) {
if (firstParameter.references.length === 0) {
context.report({ node, messageId: "expected" })
}
}
}
return {
FunctionDeclaration: checkForError,
FunctionExpression: checkForError,
ArrowFunctionExpression: checkForError,
}
},
}
-82
View File
@@ -1,82 +0,0 @@
/**
* @author Jamund Ferguson
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
docs: {
description:
"ensure Node.js-style error-first callback pattern is followed",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-callback-literal.md",
},
type: "problem",
fixable: null,
schema: [],
},
create(context) {
const callbackNames = ["callback", "cb"]
function isCallback(name) {
return callbackNames.indexOf(name) > -1
}
return {
CallExpression(node) {
const errorArg = node.arguments[0]
const calleeName = node.callee.name
if (
errorArg &&
!couldBeError(errorArg) &&
isCallback(calleeName)
) {
context.report({
node,
message:
"Unexpected literal in error position of callback.",
})
}
},
}
},
}
/**
* Determine if a node has a possiblity to be an Error object
* @param {ASTNode} node ASTNode to check
* @returns {boolean} True if there is a chance it contains an Error obj
*/
function couldBeError(node) {
switch (node.type) {
case "Identifier":
case "CallExpression":
case "NewExpression":
case "MemberExpression":
case "TaggedTemplateExpression":
case "YieldExpression":
return true // possibly an error object.
case "AssignmentExpression":
return couldBeError(node.right)
case "SequenceExpression": {
const exprs = node.expressions
return exprs.length !== 0 && couldBeError(exprs[exprs.length - 1])
}
case "LogicalExpression":
return couldBeError(node.left) || couldBeError(node.right)
case "ConditionalExpression":
return couldBeError(node.consequent) || couldBeError(node.alternate)
default:
return node.value === null
}
}
-782
View File
@@ -1,782 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { CALL, CONSTRUCT, READ, ReferenceTracker } = require("eslint-utils")
const enumeratePropertyNames = require("../util/enumerate-property-names")
const getConfiguredNodeVersion = require("../util/get-configured-node-version")
const getSemverRange = require("../util/get-semver-range")
const modules = {
_linklist: {
[READ]: { since: "5.0.0", replacedBy: null },
},
//eslint-disable-next-line camelcase
_stream_wrap: {
[READ]: { since: "12.0.0", replacedBy: null },
},
//eslint-disable-next-line camelcase
async_hooks: {
currentId: {
[READ]: {
since: "8.2.0",
replacedBy: [
{
name: "'async_hooks.executionAsyncId()'",
supported: "8.1.0",
},
],
},
},
triggerId: {
[READ]: {
since: "8.2.0",
replacedBy: "'async_hooks.triggerAsyncId()'",
},
},
},
buffer: {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
},
SlowBuffer: {
[READ]: {
since: "6.0.0",
replacedBy: [
{
name: "'buffer.Buffer.allocUnsafeSlow()'",
supported: "5.12.0",
},
],
},
},
},
constants: {
[READ]: {
since: "6.3.0",
replacedBy: "'constants' property of each module",
},
},
crypto: {
_toBuf: {
[READ]: { since: "11.0.0", replacedBy: null },
},
Credentials: {
[READ]: { since: "0.12.0", replacedBy: "'tls.SecureContext'" },
},
DEFAULT_ENCODING: {
[READ]: { since: "10.0.0", replacedBy: null },
},
createCipher: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'crypto.createCipheriv()'", supported: "0.1.94" },
],
},
},
createCredentials: {
[READ]: {
since: "0.12.0",
replacedBy: [
{
name: "'tls.createSecureContext()'",
supported: "0.11.13",
},
],
},
},
createDecipher: {
[READ]: {
since: "10.0.0",
replacedBy: [
{
name: "'crypto.createDecipheriv()'",
supported: "0.1.94",
},
],
},
},
fips: {
[READ]: {
since: "10.0.0",
replacedBy: [
{
name: "'crypto.getFips()' and 'crypto.setFips()'",
supported: "10.0.0",
},
],
},
},
prng: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
pseudoRandomBytes: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
rng: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
},
domain: {
[READ]: { since: "4.0.0", replacedBy: null },
},
events: {
EventEmitter: {
listenerCount: {
[READ]: {
since: "4.0.0",
replacedBy: [
{
name: "'events.EventEmitter#listenerCount()'",
supported: "3.2.0",
},
],
},
},
},
listenerCount: {
[READ]: {
since: "4.0.0",
replacedBy: [
{
name: "'events.EventEmitter#listenerCount()'",
supported: "3.2.0",
},
],
},
},
},
freelist: {
[READ]: { since: "4.0.0", replacedBy: null },
},
fs: {
SyncWriteStream: {
[READ]: { since: "4.0.0", replacedBy: null },
},
exists: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'fs.stat()'", supported: "0.0.2" },
{ name: "'fs.access()'", supported: "0.11.15" },
],
},
},
lchmod: {
[READ]: { since: "0.4.0", replacedBy: null },
},
lchmodSync: {
[READ]: { since: "0.4.0", replacedBy: null },
},
},
http: {
createClient: {
[READ]: {
since: "0.10.0",
replacedBy: [{ name: "'http.request()'", supported: "0.3.6" }],
},
},
},
module: {
Module: {
createRequireFromPath: {
[READ]: {
since: "12.2.0",
replacedBy: [
{
name: "'module.createRequire()'",
supported: "12.2.0",
},
],
},
},
requireRepl: {
[READ]: {
since: "6.0.0",
replacedBy: "'require(\"repl\")'",
},
},
_debug: {
[READ]: { since: "9.0.0", replacedBy: null },
},
},
createRequireFromPath: {
[READ]: {
since: "12.2.0",
replacedBy: [
{
name: "'module.createRequire()'",
supported: "12.2.0",
},
],
},
},
requireRepl: {
[READ]: {
since: "6.0.0",
replacedBy: "'require(\"repl\")'",
},
},
_debug: {
[READ]: { since: "9.0.0", replacedBy: null },
},
},
net: {
_setSimultaneousAccepts: {
[READ]: { since: "12.0.0", replacedBy: null },
},
},
os: {
getNetworkInterfaces: {
[READ]: {
since: "0.6.0",
replacedBy: [
{ name: "'os.networkInterfaces()'", supported: "0.6.0" },
],
},
},
tmpDir: {
[READ]: {
since: "7.0.0",
replacedBy: [{ name: "'os.tmpdir()'", supported: "0.9.9" }],
},
},
},
path: {
_makeLong: {
[READ]: {
since: "9.0.0",
replacedBy: [
{ name: "'path.toNamespacedPath()'", supported: "9.0.0" },
],
},
},
},
process: {
EventEmitter: {
[READ]: {
since: "0.6.0",
replacedBy: "'require(\"events\")'",
},
},
assert: {
[READ]: {
since: "10.0.0",
replacedBy: "'require(\"assert\")'",
},
},
binding: {
[READ]: { since: "10.9.0", replacedBy: null },
},
env: {
NODE_REPL_HISTORY_FILE: {
[READ]: {
since: "4.0.0",
replacedBy: "'NODE_REPL_HISTORY'",
},
},
},
report: {
triggerReport: {
[READ]: {
since: "11.12.0",
replacedBy: "'process.report.writeReport()'",
},
},
},
},
punycode: {
[READ]: {
since: "7.0.0",
replacedBy: "'https://www.npmjs.com/package/punycode'",
},
},
readline: {
codePointAt: {
[READ]: { since: "4.0.0", replacedBy: null },
},
getStringWidth: {
[READ]: { since: "6.0.0", replacedBy: null },
},
isFullWidthCodePoint: {
[READ]: { since: "6.0.0", replacedBy: null },
},
stripVTControlCharacters: {
[READ]: { since: "6.0.0", replacedBy: null },
},
},
// safe-buffer.Buffer function/constructror is just a re-export of buffer.Buffer
// and should be deprecated likewise.
"safe-buffer": {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
},
SlowBuffer: {
[READ]: {
since: "6.0.0",
replacedBy: [
{
name: "'buffer.Buffer.allocUnsafeSlow()'",
supported: "5.12.0",
},
],
},
},
},
sys: {
[READ]: {
since: "0.3.0",
replacedBy: "'util' module",
},
},
timers: {
enroll: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'setTimeout()'", supported: "0.0.1" },
{ name: "'setInterval()'", supported: "0.0.1" },
],
},
},
unenroll: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'clearTimeout()'", supported: "0.0.1" },
{ name: "'clearInterval()'", supported: "0.0.1" },
],
},
},
},
tls: {
CleartextStream: {
[READ]: { since: "0.10.0", replacedBy: null },
},
CryptoStream: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
SecurePair: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
convertNPNProtocols: {
[READ]: { since: "10.0.0", replacedBy: null },
},
createSecurePair: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
parseCertString: {
[READ]: {
since: "8.6.0",
replacedBy: [
{ name: "'querystring.parse()'", supported: "0.1.25" },
],
},
},
},
tty: {
setRawMode: {
[READ]: {
since: "0.10.0",
replacedBy:
"'tty.ReadStream#setRawMode()' (e.g. 'process.stdin.setRawMode()')",
},
},
},
url: {
parse: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'url.URL' constructor", supported: "6.13.0" },
],
},
},
resolve: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'url.URL' constructor", supported: "6.13.0" },
],
},
},
},
util: {
debug: {
[READ]: {
since: "0.12.0",
replacedBy: [
{ name: "'console.error()'", supported: "0.1.100" },
],
},
},
error: {
[READ]: {
since: "0.12.0",
replacedBy: [
{ name: "'console.error()'", supported: "0.1.100" },
],
},
},
isArray: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'Array.isArray()'", supported: "0.1.100" },
],
},
},
isBoolean: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isBuffer: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'Buffer.isBuffer()'", supported: "0.1.101" },
],
},
},
isDate: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isError: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isFunction: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNull: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNullOrUndefined: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNumber: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isObject: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isPrimitive: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isRegExp: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isString: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isSymbol: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isUndefined: {
[READ]: { since: "4.0.0", replacedBy: null },
},
log: {
[READ]: { since: "6.0.0", replacedBy: "a third party module" },
},
print: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
},
},
pump: {
[READ]: {
since: "0.10.0",
replacedBy: [
{ name: "'stream.Readable#pipe()'", supported: "0.9.4" },
],
},
},
puts: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
},
},
_extend: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'Object.assign()'", supported: "4.0.0" }],
},
},
},
vm: {
runInDebugContext: {
[READ]: { since: "8.0.0", replacedBy: null },
},
},
}
const globals = {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'Buffer.alloc()'", supported: "5.10.0" },
{ name: "'Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'Buffer.alloc()'", supported: "5.10.0" },
{ name: "'Buffer.from()'", supported: "5.10.0" },
],
},
},
COUNTER_NET_SERVER_CONNECTION: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_NET_SERVER_CONNECTION_CLOSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_SERVER_REQUEST: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_SERVER_RESPONSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_CLIENT_REQUEST: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_CLIENT_RESPONSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
GLOBAL: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'global'", supported: "0.1.27" }],
},
},
Intl: {
v8BreakIterator: {
[READ]: { since: "7.0.0", replacedBy: null },
},
},
require: {
extensions: {
[READ]: {
since: "0.12.0",
replacedBy: "compiling them ahead of time",
},
},
},
root: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'global'", supported: "0.1.27" }],
},
},
process: modules.process,
}
/**
* Makes a replacement message.
*
* @param {string|array|null} replacedBy - The text of substitute way.
* @param {Range} version - The configured version range
* @returns {string} Replacement message.
*/
function toReplaceMessage(replacedBy, version) {
let message = replacedBy
if (Array.isArray(replacedBy)) {
message = replacedBy
.filter(
({ supported }) =>
!version.intersects(getSemverRange(`<${supported}`))
)
.map(({ name }) => name)
.join(" or ")
}
return message ? `. Use ${message} instead` : ""
}
/**
* Convert a given path to name.
* @param {symbol} type The report type.
* @param {string[]} path The property access path.
* @returns {string} The name.
*/
function toName(type, path) {
const baseName = path.join(".")
return type === ReferenceTracker.CALL
? `${baseName}()`
: type === ReferenceTracker.CONSTRUCT
? `new ${baseName}()`
: baseName
}
/**
* Parses the options.
* @param {RuleContext} context The rule context.
* @returns {{version:Range,ignoredGlobalItems:Set<string>,ignoredModuleItems:Set<string>}} Parsed
* value.
*/
function parseOptions(context) {
const raw = context.options[0] || {}
const filePath = context.getFilename()
const version = getConfiguredNodeVersion(raw.version, filePath)
const ignoredModuleItems = new Set(raw.ignoreModuleItems || [])
const ignoredGlobalItems = new Set(raw.ignoreGlobalItems || [])
return Object.freeze({ version, ignoredGlobalItems, ignoredModuleItems })
}
module.exports = {
meta: {
docs: {
description: "disallow deprecated APIs",
category: "Best Practices",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-deprecated-api.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
version: {
type: "string",
},
ignoreModuleItems: {
type: "array",
items: {
enum: Array.from(enumeratePropertyNames(modules)),
},
additionalItems: false,
uniqueItems: true,
},
ignoreGlobalItems: {
type: "array",
items: {
enum: Array.from(enumeratePropertyNames(globals)),
},
additionalItems: false,
uniqueItems: true,
},
// Deprecated since v4.2.0
ignoreIndirectDependencies: { type: "boolean" },
},
additionalProperties: false,
},
],
},
create(context) {
const {
ignoredModuleItems,
ignoredGlobalItems,
version,
} = parseOptions(context)
/**
* Reports a use of a deprecated API.
*
* @param {ASTNode} node - A node to report.
* @param {string} name - The name of a deprecated API.
* @param {{since: number, replacedBy: string}} info - Information of the API.
* @returns {void}
*/
function reportItem(node, name, info) {
context.report({
node,
loc: node.loc,
message:
"{{name}} was deprecated since v{{version}}{{replace}}.",
data: {
name,
version: info.since,
replace: toReplaceMessage(info.replacedBy, version),
},
})
}
return {
"Program:exit"() {
const tracker = new ReferenceTracker(context.getScope(), {
mode: "legacy",
})
for (const report of tracker.iterateGlobalReferences(globals)) {
const { node, path, type, info } = report
const name = toName(type, path)
if (!ignoredGlobalItems.has(name)) {
reportItem(node, `'${name}'`, info)
}
}
for (const report of [
...tracker.iterateCjsReferences(modules),
...tracker.iterateEsmReferences(modules),
]) {
const { node, path, type, info } = report
const name = toName(type, path)
const suffix = path.length === 1 ? " module" : ""
if (!ignoredModuleItems.has(name)) {
reportItem(node, `'${name}'${suffix}`, info)
}
}
},
}
},
}
-75
View File
@@ -1,75 +0,0 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
"use strict"
const { findVariable } = require("eslint-utils")
function isExports(node, scope) {
let variable = null
return (
node != null &&
node.type === "Identifier" &&
node.name === "exports" &&
(variable = findVariable(scope, node)) != null &&
variable.scope.type === "global"
)
}
function isModuleExports(node, scope) {
let variable = null
return (
node != null &&
node.type === "MemberExpression" &&
!node.computed &&
node.object.type === "Identifier" &&
node.object.name === "module" &&
node.property.type === "Identifier" &&
node.property.name === "exports" &&
(variable = findVariable(scope, node.object)) != null &&
variable.scope.type === "global"
)
}
module.exports = {
meta: {
docs: {
description: "disallow the assignment to `exports`",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-exports-assign.md",
},
fixable: null,
messages: {
forbidden:
"Unexpected assignment to 'exports' variable. Use 'module.exports' instead.",
},
schema: [],
type: "problem",
},
create(context) {
return {
AssignmentExpression(node) {
const scope = context.getScope()
if (
!isExports(node.left, scope) ||
// module.exports = exports = {}
(node.parent.type === "AssignmentExpression" &&
node.parent.right === node &&
isModuleExports(node.parent.left, scope)) ||
// exports = module.exports = {}
(node.right.type === "AssignmentExpression" &&
isModuleExports(node.right.left, scope))
) {
return
}
context.report({ node, messageId: "forbidden" })
},
}
},
}
-49
View File
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkExtraneous = require("../util/check-extraneous")
const getAllowModules = require("../util/get-allow-modules")
const getConvertPath = require("../util/get-convert-path")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")
module.exports = {
meta: {
docs: {
description:
"disallow `import` declarations which import extraneous modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-extraneous-import.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
convertPath: getConvertPath.schema,
resolvePaths: getResolvePaths.schema,
tryExtensions: getTryExtensions.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitImport(context, {}, targets => {
checkExtraneous(context, filePath, targets)
})
},
}
-49
View File
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkExtraneous = require("../util/check-extraneous")
const getAllowModules = require("../util/get-allow-modules")
const getConvertPath = require("../util/get-convert-path")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitRequire = require("../util/visit-require")
module.exports = {
meta: {
docs: {
description:
"disallow `require()` expressions which import extraneous modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-extraneous-require.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
convertPath: getConvertPath.schema,
resolvePaths: getResolvePaths.schema,
tryExtensions: getTryExtensions.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitRequire(context, {}, targets => {
checkExtraneous(context, filePath, targets)
})
},
}
-157
View File
@@ -1,157 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*
* @deprecated since v4.2.0
* This rule was based on an invalid assumption.
* No meaning.
*/
"use strict"
const path = require("path")
const resolve = require("resolve")
const getPackageJson = require("../util/get-package-json")
const mergeVisitorsInPlace = require("../util/merge-visitors-in-place")
const visitImport = require("../util/visit-import")
const visitRequire = require("../util/visit-require")
const CORE_MODULES = new Set([
"assert",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"dns",
/* "domain", */ "events",
"fs",
"http",
"https",
"module",
"net",
"os",
"path",
/* "punycode", */ "querystring",
"readline",
"repl",
"stream",
"string_decoder",
"timers",
"tls",
"tty",
"url",
"util",
"vm",
"zlib",
])
const BACK_SLASH = /\\/gu
module.exports = {
meta: {
docs: {
description:
"disallow third-party modules which are hiding core modules",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-hide-core-modules.md",
},
type: "problem",
deprecated: true,
fixable: null,
schema: [
{
type: "object",
properties: {
allow: {
type: "array",
items: { enum: Array.from(CORE_MODULES) },
additionalItems: false,
uniqueItems: true,
},
ignoreDirectDependencies: { type: "boolean" },
ignoreIndirectDependencies: { type: "boolean" },
},
additionalProperties: false,
},
],
},
create(context) {
if (context.getFilename() === "<input>") {
return {}
}
const filePath = path.resolve(context.getFilename())
const dirPath = path.dirname(filePath)
const packageJson = getPackageJson(filePath)
const deps = new Set(
[].concat(
Object.keys((packageJson && packageJson.dependencies) || {}),
Object.keys((packageJson && packageJson.devDependencies) || {})
)
)
const options = context.options[0] || {}
const allow = options.allow || []
const ignoreDirectDependencies = Boolean(
options.ignoreDirectDependencies
)
const ignoreIndirectDependencies = Boolean(
options.ignoreIndirectDependencies
)
const targets = []
return [
visitImport(context, { includeCore: true }, importTargets =>
targets.push(...importTargets)
),
visitRequire(context, { includeCore: true }, requireTargets =>
targets.push(...requireTargets)
),
{
"Program:exit"() {
for (const target of targets.filter(
t =>
CORE_MODULES.has(t.moduleName) &&
t.moduleName === t.name
)) {
const name = target.moduleName
const allowed =
allow.indexOf(name) !== -1 ||
(ignoreDirectDependencies && deps.has(name)) ||
(ignoreIndirectDependencies && !deps.has(name))
if (allowed) {
continue
}
let resolved = ""
try {
resolved = resolve.sync(`${name}/`, {
basedir: dirPath,
})
} catch (_error) {
continue
}
context.report({
node: target.node,
loc: target.node.loc,
message:
"Unexpected import of third-party module '{{name}}'.",
data: {
name: path
.relative(dirPath, resolved)
.replace(BACK_SLASH, "/"),
},
})
}
},
},
].reduce(
(mergedVisitor, thisVisitor) =>
mergeVisitorsInPlace(mergedVisitor, thisVisitor),
{}
)
},
}
-47
View File
@@ -1,47 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkExistence = require("../util/check-existence")
const getAllowModules = require("../util/get-allow-modules")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")
module.exports = {
meta: {
docs: {
description:
"disallow `import` declarations which import non-existence modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-missing-import.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
tryExtensions: getTryExtensions.schema,
resolvePaths: getResolvePaths.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitImport(context, {}, targets => {
checkExistence(context, targets)
})
},
}
-47
View File
@@ -1,47 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkExistence = require("../util/check-existence")
const getAllowModules = require("../util/get-allow-modules")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitRequire = require("../util/visit-require")
module.exports = {
meta: {
docs: {
description:
"disallow `require()` expressions which import non-existence modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-missing-require.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
tryExtensions: getTryExtensions.schema,
resolvePaths: getResolvePaths.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitRequire(context, {}, targets => {
checkExistence(context, targets)
})
},
}
-255
View File
@@ -1,255 +0,0 @@
/**
* @author Raphael Pigulla
* See LICENSE file in root directory for full license.
*/
"use strict"
// This list is generated using:
// `require("module").builtinModules`
//
// This was last updated using Node v13.8.0.
const BUILTIN_MODULES = [
"_http_agent",
"_http_client",
"_http_common",
"_http_incoming",
"_http_outgoing",
"_http_server",
"_stream_duplex",
"_stream_passthrough",
"_stream_readable",
"_stream_transform",
"_stream_wrap",
"_stream_writable",
"_tls_common",
"_tls_wrap",
"assert",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"dns",
"domain",
"events",
"fs",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"string_decoder",
"sys",
"timers",
"tls",
"trace_events",
"tty",
"url",
"util",
"v8",
"vm",
"worker_threads",
"zlib",
]
module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"disallow `require` calls to be mixed with regular variable declarations",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-mixed-requires.md",
},
fixable: null,
schema: [
{
oneOf: [
{
type: "boolean",
},
{
type: "object",
properties: {
grouping: {
type: "boolean",
},
allowCall: {
type: "boolean",
},
},
additionalProperties: false,
},
],
},
],
messages: {
noMixRequire: "Do not mix 'require' and other declarations.",
noMixCoreModuleFileComputed:
"Do not mix core, module, file and computed requires.",
},
},
create(context) {
const options = context.options[0]
let grouping = false
let allowCall = false
if (typeof options === "object") {
grouping = options.grouping
allowCall = options.allowCall
} else {
grouping = Boolean(options)
}
const DECL_REQUIRE = "require"
const DECL_UNINITIALIZED = "uninitialized"
const DECL_OTHER = "other"
const REQ_CORE = "core"
const REQ_FILE = "file"
const REQ_MODULE = "module"
const REQ_COMPUTED = "computed"
/**
* Determines the type of a declaration statement.
* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string} The type of declaration represented by the expression.
*/
function getDeclarationType(initExpression) {
if (!initExpression) {
// "var x;"
return DECL_UNINITIALIZED
}
if (
initExpression.type === "CallExpression" &&
initExpression.callee.type === "Identifier" &&
initExpression.callee.name === "require"
) {
// "var x = require('util');"
return DECL_REQUIRE
}
if (
allowCall &&
initExpression.type === "CallExpression" &&
initExpression.callee.type === "CallExpression"
) {
// "var x = require('diagnose')('sub-module');"
return getDeclarationType(initExpression.callee)
}
if (initExpression.type === "MemberExpression") {
// "var x = require('glob').Glob;"
return getDeclarationType(initExpression.object)
}
// "var x = 42;"
return DECL_OTHER
}
/**
* Determines the type of module that is loaded via require.
* @param {ASTNode} initExpression The init node of the VariableDeclarator.
* @returns {string} The module type.
*/
function inferModuleType(initExpression) {
if (initExpression.type === "MemberExpression") {
// "var x = require('glob').Glob;"
return inferModuleType(initExpression.object)
}
if (initExpression.arguments.length === 0) {
// "var x = require();"
return REQ_COMPUTED
}
const arg = initExpression.arguments[0]
if (arg.type !== "Literal" || typeof arg.value !== "string") {
// "var x = require(42);"
return REQ_COMPUTED
}
if (BUILTIN_MODULES.indexOf(arg.value) !== -1) {
// "var fs = require('fs');"
return REQ_CORE
}
if (/^\.{0,2}\//u.test(arg.value)) {
// "var utils = require('./utils');"
return REQ_FILE
}
// "var async = require('async');"
return REQ_MODULE
}
/**
* Check if the list of variable declarations is mixed, i.e. whether it
* contains both require and other declarations.
* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean} True if the declarations are mixed, false if not.
*/
function isMixed(declarations) {
const contains = {}
for (const declaration of declarations) {
const type = getDeclarationType(declaration.init)
contains[type] = true
}
return Boolean(
contains[DECL_REQUIRE] &&
(contains[DECL_UNINITIALIZED] || contains[DECL_OTHER])
)
}
/**
* Check if all require declarations in the given list are of the same
* type.
* @param {ASTNode} declarations The list of VariableDeclarators.
* @returns {boolean} True if the declarations are grouped, false if not.
*/
function isGrouped(declarations) {
const found = {}
for (const declaration of declarations) {
if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
found[inferModuleType(declaration.init)] = true
}
}
return Object.keys(found).length <= 1
}
return {
VariableDeclaration(node) {
if (isMixed(node.declarations)) {
context.report({
node,
messageId: "noMixRequire",
})
} else if (grouping && !isGrouped(node.declarations)) {
context.report({
node,
messageId: "noMixCoreModuleFileComputed",
})
}
},
}
},
}
-39
View File
@@ -1,39 +0,0 @@
/**
* @author Wil Moore III
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow `new` operators with calls to `require`",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-new-require.md",
},
fixable: null,
schema: [],
messages: {
noNewRequire: "Unexpected use of new with require.",
},
},
create(context) {
return {
NewExpression(node) {
if (
node.callee.type === "Identifier" &&
node.callee.name === "require"
) {
context.report({
node,
messageId: "noNewRequire",
})
}
},
}
},
}
-212
View File
@@ -1,212 +0,0 @@
/**
* @author Nicholas C. Zakas
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const { READ, ReferenceTracker, getStringIfConstant } = require("eslint-utils")
/**
* Get the first char of the specified template element.
* @param {TemplateLiteral} node The `TemplateLiteral` node to get.
* @param {number} i The number of template elements to get first char.
* @param {Set<Node>} sepNodes The nodes of `path.sep`.
* @param {import("escope").Scope} globalScope The global scope object.
* @param {string[]} outNextChars The array to collect chars.
* @returns {void}
*/
function collectFirstCharsOfTemplateElement(
node,
i,
sepNodes,
globalScope,
outNextChars
) {
const element = node.quasis[i].value.cooked
if (element == null) {
return
}
if (element !== "") {
outNextChars.push(element[0])
return
}
if (node.expressions.length > i) {
collectFirstChars(
node.expressions[i],
sepNodes,
globalScope,
outNextChars
)
}
}
/**
* Get the first char of a given node.
* @param {TemplateLiteral} node The `TemplateLiteral` node to get.
* @param {Set<Node>} sepNodes The nodes of `path.sep`.
* @param {import("escope").Scope} globalScope The global scope object.
* @param {string[]} outNextChars The array to collect chars.
* @returns {void}
*/
function collectFirstChars(node, sepNodes, globalScope, outNextChars) {
switch (node.type) {
case "AssignmentExpression":
collectFirstChars(node.right, sepNodes, globalScope, outNextChars)
break
case "BinaryExpression":
collectFirstChars(node.left, sepNodes, globalScope, outNextChars)
break
case "ConditionalExpression":
collectFirstChars(
node.consequent,
sepNodes,
globalScope,
outNextChars
)
collectFirstChars(
node.alternate,
sepNodes,
globalScope,
outNextChars
)
break
case "LogicalExpression":
collectFirstChars(node.left, sepNodes, globalScope, outNextChars)
collectFirstChars(node.right, sepNodes, globalScope, outNextChars)
break
case "SequenceExpression":
collectFirstChars(
node.expressions[node.expressions.length - 1],
sepNodes,
globalScope,
outNextChars
)
break
case "TemplateLiteral":
collectFirstCharsOfTemplateElement(
node,
0,
sepNodes,
globalScope,
outNextChars
)
break
case "Identifier":
case "MemberExpression":
if (sepNodes.has(node)) {
outNextChars.push(path.sep)
break
}
// fallthrough
default: {
const str = getStringIfConstant(node, globalScope)
if (str) {
outNextChars.push(str[0])
}
}
}
}
/**
* Check if a char is a path separator or not.
* @param {string} c The char to check.
* @returns {boolean} `true` if the char is a path separator.
*/
function isPathSeparator(c) {
return c === "/" || c === path.sep
}
/**
* Check if the given Identifier node is followed by string concatenation with a
* path separator.
* @param {Identifier} node The `__dirname` or `__filename` node to check.
* @param {Set<Node>} sepNodes The nodes of `path.sep`.
* @param {import("escope").Scope} globalScope The global scope object.
* @returns {boolean} `true` if the given Identifier node is followed by string
* concatenation with a path separator.
*/
function isConcat(node, sepNodes, globalScope) {
const parent = node.parent
const nextChars = []
if (
parent.type === "BinaryExpression" &&
parent.operator === "+" &&
parent.left === node
) {
collectFirstChars(
parent.right,
sepNodes,
globalScope,
/* out */ nextChars
)
} else if (parent.type === "TemplateLiteral") {
collectFirstCharsOfTemplateElement(
parent,
parent.expressions.indexOf(node) + 1,
sepNodes,
globalScope,
/* out */ nextChars
)
}
return nextChars.some(isPathSeparator)
}
module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"disallow string concatenation with `__dirname` and `__filename`",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-path-concat.md",
},
fixable: null,
schema: [],
messages: {
usePathFunctions:
"Use path.join() or path.resolve() instead of string concatenation.",
},
},
create(context) {
return {
"Program:exit"() {
const globalScope = context.getScope()
const tracker = new ReferenceTracker(globalScope)
const sepNodes = new Set()
// Collect `paht.sep` references
for (const { node } of tracker.iterateCjsReferences({
path: { sep: { [READ]: true } },
})) {
sepNodes.add(node)
}
for (const { node } of tracker.iterateEsmReferences({
path: { sep: { [READ]: true } },
})) {
sepNodes.add(node)
}
// Verify `__dirname` and `__filename`
for (const { node } of tracker.iterateGlobalReferences({
__dirname: { [READ]: true },
__filename: { [READ]: true },
})) {
if (isConcat(node, sepNodes, globalScope)) {
context.report({
node: node.parent,
messageId: "usePathFunctions",
})
}
}
},
}
},
}
-45
View File
@@ -1,45 +0,0 @@
/**
* @author Vignesh Anand
* See LICENSE file in root directory for full license.
*/
"use strict"
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow the use of `process.env`",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-env.md",
},
fixable: null,
schema: [],
messages: {
unexpectedProcessEnv: "Unexpected use of process.env.",
},
},
create(context) {
return {
MemberExpression(node) {
const objectName = node.object.name
const propertyName = node.property.name
if (
objectName === "process" &&
!node.computed &&
propertyName &&
propertyName === "env"
) {
context.report({ node, messageId: "unexpectedProcessEnv" })
}
},
}
},
}
-36
View File
@@ -1,36 +0,0 @@
/**
* @author Nicholas C. Zakas
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow the use of `process.exit()`",
category: "Possible Errors",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-exit.md",
},
fixable: null,
schema: [],
messages: {
noProcessExit: "Don't use process.exit(); throw an error instead.",
},
},
create(context) {
return {
"CallExpression > MemberExpression.callee[object.name = 'process'][property.name = 'exit']"(
node
) {
context.report({
node: node.parent,
messageId: "noProcessExit",
})
},
}
},
}
-61
View File
@@ -1,61 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const check = require("../util/check-restricted")
const visit = require("../util/visit-import")
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow specified modules when loaded by `require`",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-import.md",
},
fixable: null,
schema: [
{
type: "array",
items: {
anyOf: [
{ type: "string" },
{
type: "object",
properties: {
name: {
anyOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
additionalItems: false,
},
],
},
message: { type: "string" },
},
additionalProperties: false,
required: ["name"],
},
],
},
additionalItems: false,
},
],
messages: {
restricted:
// eslint-disable-next-line @mysticatea/eslint-plugin/report-message-format
"'{{name}}' module is restricted from being used.{{customMessage}}",
},
},
create(context) {
const opts = { includeCore: true }
return visit(context, opts, targets => check(context, targets))
},
}
-62
View File
@@ -1,62 +0,0 @@
/**
* @author Christian Schulz
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const check = require("../util/check-restricted")
const visit = require("../util/visit-require")
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow specified modules when loaded by `require`",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-require.md",
},
fixable: null,
schema: [
{
type: "array",
items: {
anyOf: [
{ type: "string" },
{
type: "object",
properties: {
name: {
anyOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
additionalItems: false,
},
],
},
message: { type: "string" },
},
additionalProperties: false,
required: ["name"],
},
],
},
additionalItems: false,
},
],
messages: {
restricted:
// eslint-disable-next-line @mysticatea/eslint-plugin/report-message-format
"'{{name}}' module is restricted from being used.{{customMessage}}",
},
},
create(context) {
const opts = { includeCore: true }
return visit(context, opts, targets => check(context, targets))
},
}
-53
View File
@@ -1,53 +0,0 @@
/**
* @author Matt DuVall<http://mattduvall.com/>
* See LICENSE file in root directory for full license.
*/
"use strict"
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow synchronous methods",
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-sync.md",
},
fixable: null,
schema: [
{
type: "object",
properties: {
allowAtRootLevel: {
type: "boolean",
default: false,
},
},
additionalProperties: false,
},
],
messages: {
noSync: "Unexpected sync method: '{{propertyName}}'.",
},
},
create(context) {
const selector =
context.options[0] && context.options[0].allowAtRootLevel
? ":function MemberExpression[property.name=/.*Sync$/]"
: "MemberExpression[property.name=/.*Sync$/]"
return {
[selector](node) {
context.report({
node,
messageId: "noSync",
data: {
propertyName: node.property.name,
},
})
},
}
},
}
-97
View File
@@ -1,97 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const getConvertPath = require("../util/get-convert-path")
const getNpmignore = require("../util/get-npmignore")
const getPackageJson = require("../util/get-package-json")
/**
* Checks whether or not a given path is a `bin` file.
*
* @param {string} filePath - A file path to check.
* @param {string|object|undefined} binField - A value of the `bin` field of `package.json`.
* @param {string} basedir - A directory path that `package.json` exists.
* @returns {boolean} `true` if the file is a `bin` file.
*/
function isBinFile(filePath, binField, basedir) {
if (!binField) {
return false
}
if (typeof binField === "string") {
return filePath === path.resolve(basedir, binField)
}
return Object.keys(binField).some(
key => filePath === path.resolve(basedir, binField[key])
)
}
module.exports = {
meta: {
docs: {
description: "disallow `bin` files that npm ignores",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unpublished-bin.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
//
convertPath: getConvertPath.schema,
},
},
],
},
create(context) {
return {
Program(node) {
// Check file path.
let rawFilePath = context.getFilename()
if (rawFilePath === "<input>") {
return
}
rawFilePath = path.resolve(rawFilePath)
// Find package.json
const p = getPackageJson(rawFilePath)
if (!p) {
return
}
// Convert by convertPath option
const basedir = path.dirname(p.filePath)
const relativePath = getConvertPath(context)(
path.relative(basedir, rawFilePath).replace(/\\/gu, "/")
)
const filePath = path.join(basedir, relativePath)
// Check this file is bin.
if (!isBinFile(filePath, p.bin, basedir)) {
return
}
// Check ignored or not
const npmignore = getNpmignore(filePath)
if (!npmignore.match(relativePath)) {
return
}
// Report.
context.report({
node,
message:
"npm ignores '{{name}}'. Check 'files' field of 'package.json' or '.npmignore'.",
data: { name: relativePath },
})
},
}
},
}
-49
View File
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkPublish = require("../util/check-publish")
const getAllowModules = require("../util/get-allow-modules")
const getConvertPath = require("../util/get-convert-path")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitImport = require("../util/visit-import")
module.exports = {
meta: {
docs: {
description:
"disallow `import` declarations which import private modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unpublished-import.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
convertPath: getConvertPath.schema,
resolvePaths: getResolvePaths.schema,
tryExtensions: getTryExtensions.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitImport(context, {}, targets => {
checkPublish(context, filePath, targets)
})
},
}
-49
View File
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const checkPublish = require("../util/check-publish")
const getAllowModules = require("../util/get-allow-modules")
const getConvertPath = require("../util/get-convert-path")
const getResolvePaths = require("../util/get-resolve-paths")
const getTryExtensions = require("../util/get-try-extensions")
const visitRequire = require("../util/visit-require")
module.exports = {
meta: {
docs: {
description:
"disallow `require()` expressions which import private modules",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unpublished-require.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
allowModules: getAllowModules.schema,
convertPath: getConvertPath.schema,
resolvePaths: getResolvePaths.schema,
tryExtensions: getTryExtensions.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
return visitRequire(context, {}, targets => {
checkPublish(context, filePath, targets)
})
},
}
File diff suppressed because it is too large Load Diff
@@ -1,181 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkUnsupportedBuiltins = require("../../util/check-unsupported-builtins")
const enumeratePropertyNames = require("../../util/enumerate-property-names")
const trackMap = {
globals: {
Array: {
from: { [READ]: { supported: "4.0.0" } },
of: { [READ]: { supported: "4.0.0" } },
},
BigInt: {
[READ]: { supported: "10.4.0" },
},
Map: {
[READ]: { supported: "0.12.0" },
},
Math: {
acosh: { [READ]: { supported: "0.12.0" } },
asinh: { [READ]: { supported: "0.12.0" } },
atanh: { [READ]: { supported: "0.12.0" } },
cbrt: { [READ]: { supported: "0.12.0" } },
clz32: { [READ]: { supported: "0.12.0" } },
cosh: { [READ]: { supported: "0.12.0" } },
expm1: { [READ]: { supported: "0.12.0" } },
fround: { [READ]: { supported: "0.12.0" } },
hypot: { [READ]: { supported: "0.12.0" } },
imul: { [READ]: { supported: "0.12.0" } },
log10: { [READ]: { supported: "0.12.0" } },
log1p: { [READ]: { supported: "0.12.0" } },
log2: { [READ]: { supported: "0.12.0" } },
sign: { [READ]: { supported: "0.12.0" } },
sinh: { [READ]: { supported: "0.12.0" } },
tanh: { [READ]: { supported: "0.12.0" } },
trunc: { [READ]: { supported: "0.12.0" } },
},
Number: {
EPSILON: { [READ]: { supported: "0.12.0" } },
isFinite: { [READ]: { supported: "0.10.0" } },
isInteger: { [READ]: { supported: "0.12.0" } },
isNaN: { [READ]: { supported: "0.10.0" } },
isSafeInteger: { [READ]: { supported: "0.12.0" } },
MAX_SAFE_INTEGER: { [READ]: { supported: "0.12.0" } },
MIN_SAFE_INTEGER: { [READ]: { supported: "0.12.0" } },
parseFloat: { [READ]: { supported: "0.12.0" } },
parseInt: { [READ]: { supported: "0.12.0" } },
},
Object: {
assign: { [READ]: { supported: "4.0.0" } },
fromEntries: { [READ]: { supported: "12.0.0" } },
getOwnPropertySymbols: { [READ]: { supported: "0.12.0" } },
is: { [READ]: { supported: "0.10.0" } },
setPrototypeOf: { [READ]: { supported: "0.12.0" } },
values: { [READ]: { supported: "7.0.0" } },
entries: { [READ]: { supported: "7.0.0" } },
getOwnPropertyDescriptors: { [READ]: { supported: "7.0.0" } },
},
Promise: {
[READ]: { supported: "0.12.0" },
allSettled: { [READ]: { supported: "12.9.0" } },
},
Proxy: {
[READ]: { supported: "6.0.0" },
},
Reflect: {
[READ]: { supported: "6.0.0" },
},
Set: {
[READ]: { supported: "0.12.0" },
},
String: {
fromCodePoint: { [READ]: { supported: "4.0.0" } },
raw: { [READ]: { supported: "4.0.0" } },
},
Symbol: {
[READ]: { supported: "0.12.0" },
},
Int8Array: {
[READ]: { supported: "0.10.0" },
},
Uint8Array: {
[READ]: { supported: "0.10.0" },
},
Uint8ClampedArray: {
[READ]: { supported: "0.10.0" },
},
Int16Array: {
[READ]: { supported: "0.10.0" },
},
Uint16Array: {
[READ]: { supported: "0.10.0" },
},
Int32Array: {
[READ]: { supported: "0.10.0" },
},
Uint32Array: {
[READ]: { supported: "0.10.0" },
},
BigInt64Array: {
[READ]: { supported: "10.4.0" },
},
BigUint64Array: {
[READ]: { supported: "10.4.0" },
},
Float32Array: {
[READ]: { supported: "0.10.0" },
},
Float64Array: {
[READ]: { supported: "0.10.0" },
},
DataView: {
[READ]: { supported: "0.10.0" },
},
WeakMap: {
[READ]: { supported: "0.12.0" },
},
WeakSet: {
[READ]: { supported: "0.12.0" },
},
Atomics: {
[READ]: { supported: "8.10.0" },
},
SharedArrayBuffer: {
[READ]: { supported: "8.10.0" },
},
globalThis: {
[READ]: { supported: "12.0.0" },
},
},
}
module.exports = {
meta: {
docs: {
description:
"disallow unsupported ECMAScript built-ins on the specified version",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unsupported-features/es-builtins.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
version: {
type: "string",
},
ignores: {
type: "array",
items: {
enum: Array.from(
enumeratePropertyNames(trackMap.globals)
),
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
messages: {
unsupported:
"The '{{name}}' is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
},
},
create(context) {
return {
"Program:exit"() {
checkUnsupportedBuiltins(context, trackMap)
},
}
},
}
@@ -1,637 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { rules: esRules } = require("eslint-plugin-es")
const { getInnermostScope } = require("eslint-utils")
const { Range } = require("semver") //eslint-disable-line no-unused-vars
const getConfiguredNodeVersion = require("../../util/get-configured-node-version")
const getSemverRange = require("../../util/get-semver-range")
const mergeVisitorsInPlace = require("../../util/merge-visitors-in-place")
const getOrSet = /^(?:g|s)et$/u
const features = {
//--------------------------------------------------------------------------
// ES2015
//--------------------------------------------------------------------------
arrowFunctions: {
ruleId: "no-arrow-functions",
cases: [
{
supported: "4.0.0",
messageId: "no-arrow-functions",
},
],
},
binaryNumericLiterals: {
ruleId: "no-binary-numeric-literals",
cases: [
{
supported: "4.0.0",
messageId: "no-binary-numeric-literals",
},
],
},
blockScopedFunctions: {
ruleId: "no-block-scoped-functions",
cases: [
{
supported: "6.0.0",
test: info => !info.isStrict,
messageId: "no-block-scoped-functions-sloppy",
},
{
supported: "4.0.0",
messageId: "no-block-scoped-functions-strict",
},
],
},
blockScopedVariables: {
ruleId: "no-block-scoped-variables",
cases: [
{
supported: "6.0.0",
test: info => !info.isStrict,
messageId: "no-block-scoped-variables-sloppy",
},
{
supported: "4.0.0",
messageId: "no-block-scoped-variables-strict",
},
],
},
classes: {
ruleId: "no-classes",
cases: [
{
supported: "6.0.0",
test: info => !info.isStrict,
messageId: "no-classes-sloppy",
},
{
supported: "4.0.0",
messageId: "no-classes-strict",
},
],
},
computedProperties: {
ruleId: "no-computed-properties",
cases: [
{
supported: "4.0.0",
messageId: "no-computed-properties",
},
],
},
defaultParameters: {
ruleId: "no-default-parameters",
cases: [
{
supported: "6.0.0",
messageId: "no-default-parameters",
},
],
},
destructuring: {
ruleId: "no-destructuring",
cases: [
{
supported: "6.0.0",
messageId: "no-destructuring",
},
],
},
forOfLoops: {
ruleId: "no-for-of-loops",
cases: [
{
supported: "0.12.0",
messageId: "no-for-of-loops",
},
],
},
generators: {
ruleId: "no-generators",
cases: [
{
supported: "4.0.0",
messageId: "no-generators",
},
],
},
modules: {
ruleId: "no-modules",
cases: [
{
supported: null,
messageId: "no-modules",
},
],
},
"new.target": {
ruleId: "no-new-target",
cases: [
{
supported: "5.0.0",
messageId: "no-new-target",
},
],
},
objectSuperProperties: {
ruleId: "no-object-super-properties",
cases: [
{
supported: "4.0.0",
messageId: "no-object-super-properties",
},
],
},
octalNumericLiterals: {
ruleId: "no-octal-numeric-literals",
cases: [
{
supported: "4.0.0",
messageId: "no-octal-numeric-literals",
},
],
},
propertyShorthands: {
ruleId: "no-property-shorthands",
cases: [
{
supported: "6.0.0",
test: info =>
info.node.shorthand && getOrSet.test(info.node.key.name),
messageId: "no-property-shorthands-getset",
},
{
supported: "4.0.0",
messageId: "no-property-shorthands",
},
],
},
regexpU: {
ruleId: "no-regexp-u-flag",
cases: [
{
supported: "6.0.0",
messageId: "no-regexp-u-flag",
},
],
},
regexpY: {
ruleId: "no-regexp-y-flag",
cases: [
{
supported: "6.0.0",
messageId: "no-regexp-y-flag",
},
],
},
restParameters: {
ruleId: "no-rest-parameters",
cases: [
{
supported: "6.0.0",
messageId: "no-rest-parameters",
},
],
},
spreadElements: {
ruleId: "no-spread-elements",
cases: [
{
supported: "5.0.0",
messageId: "no-spread-elements",
},
],
},
templateLiterals: {
ruleId: "no-template-literals",
cases: [
{
supported: "4.0.0",
messageId: "no-template-literals",
},
],
},
unicodeCodePointEscapes: {
ruleId: "no-unicode-codepoint-escapes",
cases: [
{
supported: "4.0.0",
messageId: "no-unicode-codepoint-escapes",
},
],
},
//--------------------------------------------------------------------------
// ES2016
//--------------------------------------------------------------------------
exponentialOperators: {
ruleId: "no-exponential-operators",
cases: [
{
supported: "7.0.0",
messageId: "no-exponential-operators",
},
],
},
//--------------------------------------------------------------------------
// ES2017
//--------------------------------------------------------------------------
asyncFunctions: {
ruleId: "no-async-functions",
cases: [
{
supported: "7.6.0",
messageId: "no-async-functions",
},
],
},
trailingCommasInFunctions: {
ruleId: "no-trailing-function-commas",
cases: [
{
supported: "8.0.0",
messageId: "no-trailing-function-commas",
},
],
},
//--------------------------------------------------------------------------
// ES2018
//--------------------------------------------------------------------------
asyncIteration: {
ruleId: "no-async-iteration",
cases: [
{
supported: "10.0.0",
messageId: "no-async-iteration",
},
],
},
malformedTemplateLiterals: {
ruleId: "no-malformed-template-literals",
cases: [
{
supported: "8.10.0",
messageId: "no-malformed-template-literals",
},
],
},
regexpLookbehind: {
ruleId: "no-regexp-lookbehind-assertions",
cases: [
{
supported: "8.10.0",
messageId: "no-regexp-lookbehind-assertions",
},
],
},
regexpNamedCaptureGroups: {
ruleId: "no-regexp-named-capture-groups",
cases: [
{
supported: "10.0.0",
messageId: "no-regexp-named-capture-groups",
},
],
},
regexpS: {
ruleId: "no-regexp-s-flag",
cases: [
{
supported: "8.10.0",
messageId: "no-regexp-s-flag",
},
],
},
regexpUnicodeProperties: {
ruleId: "no-regexp-unicode-property-escapes",
cases: [
{
supported: "10.0.0",
messageId: "no-regexp-unicode-property-escapes",
},
],
},
restSpreadProperties: {
ruleId: "no-rest-spread-properties",
cases: [
{
supported: "8.3.0",
messageId: "no-rest-spread-properties",
},
],
},
//--------------------------------------------------------------------------
// ES2019
//--------------------------------------------------------------------------
jsonSuperset: {
ruleId: "no-json-superset",
cases: [
{
supported: "10.0.0",
messageId: "no-json-superset",
},
],
},
optionalCatchBinding: {
ruleId: "no-optional-catch-binding",
cases: [
{
supported: "10.0.0",
messageId: "no-optional-catch-binding",
},
],
},
//--------------------------------------------------------------------------
// ES2020
//--------------------------------------------------------------------------
bigint: {
ruleId: "no-bigint",
cases: [
{
supported: "10.4.0",
test: info => info.node.type === "Literal",
messageId: "no-bigint",
},
{
supported: null,
test: ({ node }) =>
node.type === "Literal" &&
(node.parent.type === "Property" ||
node.parent.type === "MethodDefinition") &&
!node.parent.computed &&
node.parent.key === node,
messageId: "no-bigint-property-names",
},
],
},
dynamicImport: {
ruleId: "no-dynamic-import",
cases: [
{
supported: null,
messageId: "no-dynamic-import",
},
],
},
}
const keywords = Object.keys(features)
/**
* 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 })
}
/**
* Find the scope that a given node belongs to.
* @param {Scope} initialScope The initial scope to find.
* @param {Node} node The AST node.
* @returns {Scope} The scope that the node belongs to.
*/
function normalizeScope(initialScope, node) {
let scope = getInnermostScope(initialScope, node)
while (scope && scope.block === node) {
scope = scope.upper
}
return scope
}
/**
* Define the visitor object as merging the rules of eslint-plugin-es.
* @param {RuleContext} context The rule context.
* @param {{version:Range,ignores:Set<string>}} options The options.
* @returns {object} The defined visitor.
*/
function defineVisitor(context, options) {
const testInfoPrototype = {
get isStrict() {
return normalizeScope(context.getScope(), this.node).isStrict
},
}
/**
* Check whether a given case object is full-supported on the configured node version.
* @param {{supported:string}} aCase The case object to check.
* @returns {boolean} `true` if it's supporting.
*/
function isNotSupportingVersion(aCase) {
return (
!aCase.supported ||
options.version.intersects(getSemverRange(`<${aCase.supported}`))
)
}
/**
* Define the predicate function to check whether a given case object is supported on the configured node version.
* @param {Node} node The node which is reported.
* @returns {function(aCase:{supported:string}):boolean} The predicate function.
*/
function isNotSupportingOn(node) {
return aCase =>
isNotSupportingVersion(aCase) &&
(!aCase.test || aCase.test({ node, __proto__: testInfoPrototype }))
}
return (
keywords
// Omit full-supported features and ignored features by options
// because this rule never reports those.
.filter(
keyword =>
!options.ignores.has(keyword) &&
features[keyword].cases.some(isNotSupportingVersion)
)
// Merge remaining features with overriding `context.report()`.
.reduce((visitor, keyword) => {
const { ruleId, cases } = features[keyword]
const rule = esRules[ruleId]
const thisContext = {
__proto__: context,
// Override `context.report()` then:
// - ignore if it's supported.
// - override reporting messages.
report(descriptor) {
// Set additional information.
if (descriptor.data) {
descriptor.data.version = options.version.raw
} else {
descriptor.data = { version: options.version.raw }
}
descriptor.fix = undefined
// Test and report.
const node = descriptor.node
const hitCase = cases.find(isNotSupportingOn(node))
if (hitCase) {
descriptor.messageId = hitCase.messageId
descriptor.data.supported = hitCase.supported
super.report(descriptor)
}
},
}
return mergeVisitorsInPlace(visitor, rule.create(thisContext))
}, {})
)
}
module.exports = {
meta: {
docs: {
description:
"disallow unsupported ECMAScript syntax on the specified version",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unsupported-features/es-syntax.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
version: {
type: "string",
},
ignores: {
type: "array",
items: {
enum: Object.keys(features),
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
messages: {
//------------------------------------------------------------------
// ES2015
//------------------------------------------------------------------
"no-arrow-functions":
"Arrow functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-binary-numeric-literals":
"Binary numeric literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-block-scoped-functions-strict":
"Block-scoped functions in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-block-scoped-functions-sloppy":
"Block-scoped functions in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-block-scoped-variables-strict":
"Block-scoped variables in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-block-scoped-variables-sloppy":
"Block-scoped variables in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-classes-strict":
"Classes in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-classes-sloppy":
"Classes in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-computed-properties":
"Computed properties are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-default-parameters":
"Default parameters are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-destructuring":
"Destructuring is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-for-of-loops":
"'for-of' loops are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-generators":
"Generator functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-modules":
"Import and export declarations are not supported yet.",
"no-new-target":
"'new.target' is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-object-super-properties":
"'super' in object literals is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-octal-numeric-literals":
"Octal numeric literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-property-shorthands":
"Property shorthands are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-property-shorthands-getset":
"Property shorthands of 'get' and 'set' are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-u-flag":
"RegExp 'u' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-y-flag":
"RegExp 'y' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-rest-parameters":
"Rest parameters are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-spread-elements":
"Spread elements are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-template-literals":
"Template literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-unicode-codepoint-escapes":
"Unicode code point escapes are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
//------------------------------------------------------------------
// ES2016
//------------------------------------------------------------------
"no-exponential-operators":
"Exponential operators are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
//------------------------------------------------------------------
// ES2017
//------------------------------------------------------------------
"no-async-functions":
"Async functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-trailing-function-commas":
"Trailing commas in function syntax are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
//------------------------------------------------------------------
// ES2018
//------------------------------------------------------------------
"no-async-iteration":
"Async iteration is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-malformed-template-literals":
"Malformed template literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-lookbehind-assertions":
"RegExp lookbehind assertions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-named-capture-groups":
"RegExp named capture groups are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-s-flag":
"RegExp 's' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-regexp-unicode-property-escapes":
"RegExp Unicode property escapes are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-rest-spread-properties":
"Rest/spread properties are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
//------------------------------------------------------------------
// ES2019
//------------------------------------------------------------------
"no-json-superset":
"'\\u{{code}}' in string literals is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-optional-catch-binding":
"The omission of 'catch' binding is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
//------------------------------------------------------------------
// ES2020
//------------------------------------------------------------------
"no-bigint":
"Bigint literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
"no-bigint-property-names":
"Bigint literal property names are not supported yet.",
"no-dynamic-import":
"'import()' expressions are not supported yet.",
},
},
create(context) {
return defineVisitor(context, parseOptions(context))
},
}
@@ -1,369 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkUnsupportedBuiltins = require("../../util/check-unsupported-builtins")
const enumeratePropertyNames = require("../../util/enumerate-property-names")
/*eslint-disable camelcase */
const trackMap = {
globals: {
queueMicrotask: {
[READ]: { supported: "12.0.0", experimental: "11.0.0" },
},
require: {
resolve: {
paths: { [READ]: { supported: "8.9.0" } },
},
},
},
modules: {
assert: {
strict: {
[READ]: { supported: "9.9.0", backported: ["8.13.0"] },
doesNotReject: { [READ]: { supported: "10.0.0" } },
rejects: { [READ]: { supported: "10.0.0" } },
},
deepStrictEqual: { [READ]: { supported: "4.0.0" } },
doesNotReject: { [READ]: { supported: "10.0.0" } },
notDeepStrictEqual: { [READ]: { supported: "4.0.0" } },
rejects: { [READ]: { supported: "10.0.0" } },
},
async_hooks: {
[READ]: { supported: "8.0.0" },
createHook: { [READ]: { supported: "8.1.0" } },
},
buffer: {
Buffer: {
alloc: { [READ]: { supported: "4.5.0" } },
allocUnsafe: { [READ]: { supported: "4.5.0" } },
allocUnsafeSlow: { [READ]: { supported: "4.5.0" } },
from: { [READ]: { supported: "4.5.0" } },
},
kMaxLength: { [READ]: { supported: "3.0.0" } },
transcode: { [READ]: { supported: "7.1.0" } },
constants: { [READ]: { supported: "8.2.0" } },
},
child_process: {
ChildProcess: { [READ]: { supported: "2.2.0" } },
},
console: {
clear: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } },
count: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } },
countReset: {
[READ]: { supported: "8.3.0", backported: ["6.13.0"] },
},
debug: { [READ]: { supported: "8.0.0" } },
dirxml: { [READ]: { supported: "8.0.0" } },
group: { [READ]: { supported: "8.5.0" } },
groupCollapsed: { [READ]: { supported: "8.5.0" } },
groupEnd: { [READ]: { supported: "8.5.0" } },
table: { [READ]: { supported: "10.0.0" } },
markTimeline: { [READ]: { supported: "8.0.0" } },
profile: { [READ]: { supported: "8.0.0" } },
profileEnd: { [READ]: { supported: "8.0.0" } },
timeLog: { [READ]: { supported: "10.7.0" } },
timeStamp: { [READ]: { supported: "8.0.0" } },
timeline: { [READ]: { supported: "8.0.0" } },
timelineEnd: { [READ]: { supported: "8.0.0" } },
},
crypto: {
Certificate: {
exportChallenge: { [READ]: { supported: "9.0.0" } },
exportPublicKey: { [READ]: { supported: "9.0.0" } },
verifySpkac: { [READ]: { supported: "9.0.0" } },
},
ECDH: { [READ]: { supported: "8.8.0", backported: ["6.13.0"] } },
KeyObject: { [READ]: { supported: "11.6.0" } },
createPrivateKey: { [READ]: { supported: "11.6.0" } },
createPublicKey: { [READ]: { supported: "11.6.0" } },
createSecretKey: { [READ]: { supported: "11.6.0" } },
constants: { [READ]: { supported: "6.3.0" } },
fips: { [READ]: { supported: "6.0.0" } },
generateKeyPair: { [READ]: { supported: "10.12.0" } },
generateKeyPairSync: { [READ]: { supported: "10.12.0" } },
getCurves: { [READ]: { supported: "2.3.0" } },
getFips: { [READ]: { supported: "10.0.0" } },
privateEncrypt: { [READ]: { supported: "1.1.0" } },
publicDecrypt: { [READ]: { supported: "1.1.0" } },
randomFillSync: {
[READ]: { supported: "7.10.0", backported: ["6.13.0"] },
},
randomFill: {
[READ]: { supported: "7.10.0", backported: ["6.13.0"] },
},
scrypt: { [READ]: { supported: "10.5.0" } },
scryptSync: { [READ]: { supported: "10.5.0" } },
setFips: { [READ]: { supported: "10.0.0" } },
sign: { [READ]: { supported: "12.0.0" } },
timingSafeEqual: { [READ]: { supported: "6.6.0" } },
verify: { [READ]: { supported: "12.0.0" } },
},
dns: {
Resolver: { [READ]: { supported: "8.3.0" } },
resolvePtr: { [READ]: { supported: "6.0.0" } },
promises: {
[READ]: {
supported: "11.14.0",
backported: ["10.17.0"],
experimental: "10.6.0",
},
},
},
events: {
EventEmitter: {
once: {
[READ]: { supported: "11.13.0", backported: ["10.16.0"] },
},
},
once: { [READ]: { supported: "11.13.0", backported: ["10.16.0"] } },
},
fs: {
Dirent: { [READ]: { supported: "10.10.0" } },
copyFile: { [READ]: { supported: "8.5.0" } },
copyFileSync: { [READ]: { supported: "8.5.0" } },
mkdtemp: { [READ]: { supported: "5.10.0" } },
mkdtempSync: { [READ]: { supported: "5.10.0" } },
realpath: {
native: { [READ]: { supported: "9.2.0" } },
},
realpathSync: {
native: { [READ]: { supported: "9.2.0" } },
},
promises: {
[READ]: {
supported: "11.14.0",
backported: ["10.17.0"],
experimental: "10.1.0",
},
},
writev: { [READ]: { supported: "12.9.0" } },
writevSync: { [READ]: { supported: "12.9.0" } },
},
http2: {
[READ]: {
supported: "10.10.0",
backported: ["8.13.0"],
experimental: "8.4.0",
},
},
inspector: {
[READ]: { supported: null, experimental: "8.0.0" },
},
module: {
Module: {
builtinModules: {
[READ]: {
supported: "9.3.0",
backported: ["6.13.0", "8.10.0"],
},
},
createRequireFromPath: { [READ]: { supported: "10.12.0" } },
createRequire: { [READ]: { supported: "12.2.0" } },
syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } },
},
builtinModules: {
[READ]: {
supported: "9.3.0",
backported: ["6.13.0", "8.10.0"],
},
},
createRequireFromPath: { [READ]: { supported: "10.12.0" } },
createRequire: { [READ]: { supported: "12.2.0" } },
syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } },
},
os: {
constants: {
[READ]: { supported: "6.3.0" },
priority: { [READ]: { supported: "10.10.0" } },
},
getPriority: { [READ]: { supported: "10.10.0" } },
homedir: { [READ]: { supported: "2.3.0" } },
setPriority: { [READ]: { supported: "10.10.0" } },
userInfo: { [READ]: { supported: "6.0.0" } },
},
path: {
toNamespacedPath: { [READ]: { supported: "9.0.0" } },
},
perf_hooks: {
[READ]: { supported: "8.5.0" },
monitorEventLoopDelay: { [READ]: { supported: "11.10.0" } },
},
process: {
allowedNodeEnvironmentFlags: { [READ]: { supported: "10.10.0" } },
argv0: { [READ]: { supported: "6.4.0" } },
channel: { [READ]: { supported: "7.1.0" } },
cpuUsage: { [READ]: { supported: "6.1.0" } },
emitWarning: { [READ]: { supported: "6.0.0" } },
getegid: { [READ]: { supported: "2.0.0" } },
geteuid: { [READ]: { supported: "2.0.0" } },
hasUncaughtExceptionCaptureCallback: {
[READ]: { supported: "9.3.0" },
},
hrtime: {
bigint: { [READ]: { supported: "10.7.0" } },
},
ppid: {
[READ]: {
supported: "9.2.0",
backported: ["6.13.0", "8.10.0"],
},
},
release: { [READ]: { supported: "3.0.0" } },
report: { [READ]: { supported: null, experimental: "11.8.0" } },
resourceUsage: { [READ]: { supported: "12.6.0" } },
setegid: { [READ]: { supported: "2.0.0" } },
seteuid: { [READ]: { supported: "2.0.0" } },
setUncaughtExceptionCaptureCallback: {
[READ]: { supported: "9.3.0" },
},
stdout: {
getColorDepth: { [READ]: { supported: "9.9.0" } },
hasColor: { [READ]: { supported: "11.13.0" } },
},
stderr: {
getColorDepth: { [READ]: { supported: "9.9.0" } },
hasColor: { [READ]: { supported: "11.13.0" } },
},
},
stream: {
Readable: {
from: {
[READ]: { supported: "12.3.0", backported: ["10.17.0"] },
},
},
finished: { [READ]: { supported: "10.0.0" } },
pipeline: { [READ]: { supported: "10.0.0" } },
},
trace_events: {
[READ]: { supported: "10.0.0" },
},
url: {
URL: { [READ]: { supported: "7.0.0", backported: ["6.13.0"] } },
URLSearchParams: {
[READ]: { supported: "7.5.0", backported: ["6.13.0"] },
},
domainToASCII: { [READ]: { supported: "7.4.0" } },
domainToUnicode: { [READ]: { supported: "7.4.0" } },
},
util: {
callbackify: { [READ]: { supported: "8.2.0" } },
formatWithOptions: { [READ]: { supported: "10.0.0" } },
getSystemErrorName: {
[READ]: { supported: "9.7.0", backported: ["8.12.0"] },
},
inspect: {
custom: { [READ]: { supported: "6.6.0" } },
defaultOptions: { [READ]: { supported: "6.4.0" } },
replDefaults: { [READ]: { supported: "11.12.0" } },
},
isDeepStrictEqual: { [READ]: { supported: "9.0.0" } },
promisify: { [READ]: { supported: "8.0.0" } },
TextDecoder: {
[READ]: { supported: "8.9.0", experimental: "8.3.0" },
},
TextEncoder: {
[READ]: { supported: "8.9.0", experimental: "8.3.0" },
},
types: {
[READ]: { supported: "10.0.0" },
isBoxedPrimitive: { [READ]: { supported: "10.11.0" } },
},
},
v8: {
[READ]: { supported: "1.0.0" },
DefaultDeserializer: { [READ]: { supported: "8.0.0" } },
DefaultSerializer: { [READ]: { supported: "8.0.0" } },
Deserializer: { [READ]: { supported: "8.0.0" } },
Serializer: { [READ]: { supported: "8.0.0" } },
cachedDataVersionTag: { [READ]: { supported: "8.0.0" } },
deserialize: { [READ]: { supported: "8.0.0" } },
getHeapCodeStatistics: { [READ]: { supported: "12.8.0" } },
getHeapSnapshot: { [READ]: { supported: "11.13.0" } },
getHeapSpaceStatistics: { [READ]: { supported: "6.0.0" } },
serialize: { [READ]: { supported: "8.0.0" } },
writeHeapSnapshot: { [READ]: { supported: "11.13.0" } },
},
vm: {
Module: { [READ]: { supported: "9.6.0" } },
compileFunction: { [READ]: { supported: "10.10.0" } },
},
worker_threads: {
[READ]: { supported: "12.11.0", experimental: "10.5.0" },
},
},
}
Object.assign(trackMap.globals, {
Buffer: trackMap.modules.buffer.Buffer,
TextDecoder: {
...trackMap.modules.util.TextDecoder,
[READ]: { supported: "11.0.0" },
},
TextEncoder: {
...trackMap.modules.util.TextEncoder,
[READ]: { supported: "11.0.0" },
},
URL: {
...trackMap.modules.url.URL,
[READ]: { supported: "10.0.0" },
},
URLSearchParams: {
...trackMap.modules.url.URLSearchParams,
[READ]: { supported: "10.0.0" },
},
console: trackMap.modules.console,
process: trackMap.modules.process,
})
/*eslint-enable camelcase */
module.exports = {
meta: {
docs: {
description:
"disallow unsupported Node.js built-in APIs on the specified version",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unsupported-features/node-builtins.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
version: {
type: "string",
},
ignores: {
type: "array",
items: {
enum: Array.from(
new Set([
...enumeratePropertyNames(trackMap.globals),
...enumeratePropertyNames(trackMap.modules),
])
),
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
messages: {
unsupported:
"The '{{name}}' is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
},
},
create(context) {
return {
"Program:exit"() {
checkUnsupportedBuiltins(context, trackMap)
},
}
},
}
-49
View File
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
Buffer: { [READ]: true },
},
modules: {
buffer: {
Buffer: { [READ]: true },
},
},
}
module.exports = {
meta: {
docs: {
description:
'enforce either `Buffer` or `require("buffer").Buffer`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/buffer.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"buffer\").Buffer'. Use the global variable 'Buffer' instead.",
preferModule:
"Unexpected use of the global variable 'Buffer'. Use 'require(\"buffer\").Buffer' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
-46
View File
@@ -1,46 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
console: { [READ]: true },
},
modules: {
console: { [READ]: true },
},
}
module.exports = {
meta: {
docs: {
description: 'enforce either `console` or `require("console")`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/console.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"console\")'. Use the global variable 'console' instead.",
preferModule:
"Unexpected use of the global variable 'console'. Use 'require(\"console\")' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
-46
View File
@@ -1,46 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
process: { [READ]: true },
},
modules: {
process: { [READ]: true },
},
}
module.exports = {
meta: {
docs: {
description: 'enforce either `process` or `require("process")`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/process.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"process\")'. Use the global variable 'process' instead.",
preferModule:
"Unexpected use of the global variable 'process'. Use 'require(\"process\")' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
TextDecoder: { [READ]: true },
},
modules: {
util: {
TextDecoder: { [READ]: true },
},
},
}
module.exports = {
meta: {
docs: {
description:
'enforce either `TextDecoder` or `require("util").TextDecoder`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/text-decoder.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"util\").TextDecoder'. Use the global variable 'TextDecoder' instead.",
preferModule:
"Unexpected use of the global variable 'TextDecoder'. Use 'require(\"util\").TextDecoder' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
TextEncoder: { [READ]: true },
},
modules: {
util: {
TextEncoder: { [READ]: true },
},
},
}
module.exports = {
meta: {
docs: {
description:
'enforce either `TextEncoder` or `require("util").TextEncoder`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/text-encoder.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"util\").TextEncoder'. Use the global variable 'TextEncoder' instead.",
preferModule:
"Unexpected use of the global variable 'TextEncoder'. Use 'require(\"util\").TextEncoder' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
@@ -1,49 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
URLSearchParams: { [READ]: true },
},
modules: {
url: {
URLSearchParams: { [READ]: true },
},
},
}
module.exports = {
meta: {
docs: {
description:
'enforce either `URLSearchParams` or `require("url").URLSearchParams`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/url-search-params.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"url\").URLSearchParams'. Use the global variable 'URLSearchParams' instead.",
preferModule:
"Unexpected use of the global variable 'URLSearchParams'. Use 'require(\"url\").URLSearchParams' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
-48
View File
@@ -1,48 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { READ } = require("eslint-utils")
const checkForPreferGlobal = require("../../util/check-prefer-global")
const trackMap = {
globals: {
URL: { [READ]: true },
},
modules: {
url: {
URL: { [READ]: true },
},
},
}
module.exports = {
meta: {
docs: {
description: 'enforce either `URL` or `require("url").URL`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-global/url.md",
},
type: "suggestion",
fixable: null,
schema: [{ enum: ["always", "never"] }],
messages: {
preferGlobal:
"Unexpected use of 'require(\"url\").URL'. Use the global variable 'URL' instead.",
preferModule:
"Unexpected use of the global variable 'URL'. Use 'require(\"url\").URL' instead.",
},
},
create(context) {
return {
"Program:exit"() {
checkForPreferGlobal(context, trackMap)
},
}
},
}
-74
View File
@@ -1,74 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { CALL, CONSTRUCT, ReferenceTracker } = require("eslint-utils")
const trackMap = {
dns: {
lookup: { [CALL]: true },
lookupService: { [CALL]: true },
Resolver: { [CONSTRUCT]: true },
getServers: { [CALL]: true },
resolve: { [CALL]: true },
resolve4: { [CALL]: true },
resolve6: { [CALL]: true },
resolveAny: { [CALL]: true },
resolveCname: { [CALL]: true },
resolveMx: { [CALL]: true },
resolveNaptr: { [CALL]: true },
resolveNs: { [CALL]: true },
resolvePtr: { [CALL]: true },
resolveSoa: { [CALL]: true },
resolveSrv: { [CALL]: true },
resolveTxt: { [CALL]: true },
reverse: { [CALL]: true },
setServers: { [CALL]: true },
},
}
module.exports = {
meta: {
docs: {
description: 'enforce `require("dns").promises`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-promises/dns.md",
},
fixable: null,
messages: {
preferPromises: "Use 'dns.promises.{{name}}()' instead.",
preferPromisesNew: "Use 'new dns.promises.{{name}}()' instead.",
},
schema: [],
type: "suggestion",
},
create(context) {
return {
"Program:exit"() {
const scope = context.getScope()
const tracker = new ReferenceTracker(scope, { mode: "legacy" })
const references = [
...tracker.iterateCjsReferences(trackMap),
...tracker.iterateEsmReferences(trackMap),
]
for (const { node, path } of references) {
const name = path[path.length - 1]
const isClass = name[0] === name[0].toUpperCase()
context.report({
node,
messageId: isClass
? "preferPromisesNew"
: "preferPromises",
data: { name },
})
}
},
}
},
}
-76
View File
@@ -1,76 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { CALL, ReferenceTracker } = require("eslint-utils")
const trackMap = {
fs: {
access: { [CALL]: true },
copyFile: { [CALL]: true },
open: { [CALL]: true },
rename: { [CALL]: true },
truncate: { [CALL]: true },
rmdir: { [CALL]: true },
mkdir: { [CALL]: true },
readdir: { [CALL]: true },
readlink: { [CALL]: true },
symlink: { [CALL]: true },
lstat: { [CALL]: true },
stat: { [CALL]: true },
link: { [CALL]: true },
unlink: { [CALL]: true },
chmod: { [CALL]: true },
lchmod: { [CALL]: true },
lchown: { [CALL]: true },
chown: { [CALL]: true },
utimes: { [CALL]: true },
realpath: { [CALL]: true },
mkdtemp: { [CALL]: true },
writeFile: { [CALL]: true },
appendFile: { [CALL]: true },
readFile: { [CALL]: true },
},
}
module.exports = {
meta: {
docs: {
description: 'enforce `require("fs").promises`',
category: "Stylistic Issues",
recommended: false,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/prefer-promises/fs.md",
},
fixable: null,
messages: {
preferPromises: "Use 'fs.promises.{{name}}()' instead.",
},
schema: [],
type: "suggestion",
},
create(context) {
return {
"Program:exit"() {
const scope = context.getScope()
const tracker = new ReferenceTracker(scope, { mode: "legacy" })
const references = [
...tracker.iterateCjsReferences(trackMap),
...tracker.iterateEsmReferences(trackMap),
]
for (const { node, path } of references) {
const name = path[path.length - 1]
context.report({
node,
messageId: "preferPromises",
data: { name },
})
}
},
}
},
}
-164
View File
@@ -1,164 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const CodePathAnalyzer = safeRequire(
"eslint/lib/linter/code-path-analysis/code-path-analyzer",
"eslint/lib/code-path-analysis/code-path-analyzer"
)
const CodePathSegment = safeRequire(
"eslint/lib/linter/code-path-analysis/code-path-segment",
"eslint/lib/code-path-analysis/code-path-segment"
)
const CodePath = safeRequire(
"eslint/lib/linter/code-path-analysis/code-path",
"eslint/lib/code-path-analysis/code-path"
)
const originalLeaveNode =
CodePathAnalyzer && CodePathAnalyzer.prototype.leaveNode
/**
* Imports a specific module.
* @param {...string} moduleNames - module names to import.
* @returns {object|null} The imported object, or null.
*/
function safeRequire(...moduleNames) {
for (const moduleName of moduleNames) {
try {
return require(moduleName)
} catch (_err) {
// Ignore.
}
}
return null
}
/* istanbul ignore next */
/**
* Copied from https://github.com/eslint/eslint/blob/16fad5880bb70e9dddbeab8ed0f425ae51f5841f/lib/code-path-analysis/code-path-analyzer.js#L137
*
* @param {CodePathAnalyzer} analyzer - The instance.
* @param {ASTNode} node - The current AST node.
* @returns {void}
*/
function forwardCurrentToHead(analyzer, node) {
const codePath = analyzer.codePath
const state = CodePath.getState(codePath)
const currentSegments = state.currentSegments
const headSegments = state.headSegments
const end = Math.max(currentSegments.length, headSegments.length)
let i = 0
let currentSegment = null
let headSegment = null
// Fires leaving events.
for (i = 0; i < end; ++i) {
currentSegment = currentSegments[i]
headSegment = headSegments[i]
if (currentSegment !== headSegment && currentSegment) {
if (currentSegment.reachable) {
analyzer.emitter.emit(
"onCodePathSegmentEnd",
currentSegment,
node
)
}
}
}
// Update state.
state.currentSegments = headSegments
// Fires entering events.
for (i = 0; i < end; ++i) {
currentSegment = currentSegments[i]
headSegment = headSegments[i]
if (currentSegment !== headSegment && headSegment) {
CodePathSegment.markUsed(headSegment)
if (headSegment.reachable) {
analyzer.emitter.emit(
"onCodePathSegmentStart",
headSegment,
node
)
}
}
}
}
/**
* Checks whether a given node is `process.exit()` or not.
*
* @param {ASTNode} node - A node to check.
* @returns {boolean} `true` if the node is `process.exit()`.
*/
function isProcessExit(node) {
return (
node.type === "CallExpression" &&
node.callee.type === "MemberExpression" &&
node.callee.computed === false &&
node.callee.object.type === "Identifier" &&
node.callee.object.name === "process" &&
node.callee.property.type === "Identifier" &&
node.callee.property.name === "exit"
)
}
/**
* The function to override `CodePathAnalyzer.prototype.leaveNode` in order to
* address `process.exit()` as throw.
*
* @this CodePathAnalyzer
* @param {ASTNode} node - A node to be left.
* @returns {void}
*/
function overrideLeaveNode(node) {
if (isProcessExit(node)) {
this.currentNode = node
forwardCurrentToHead(this, node)
CodePath.getState(this.codePath).makeThrow()
this.original.leaveNode(node)
this.currentNode = null
} else {
originalLeaveNode.call(this, node)
}
}
const visitor =
CodePathAnalyzer == null
? {}
: {
Program: function installProcessExitAsThrow() {
CodePathAnalyzer.prototype.leaveNode = overrideLeaveNode
},
"Program:exit": function restoreProcessExitAsThrow() {
CodePathAnalyzer.prototype.leaveNode = originalLeaveNode
},
}
module.exports = {
meta: {
docs: {
description:
"make `process.exit()` expressions the same code path as `throw`",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/process-exit-as-throw.md",
},
type: "problem",
fixable: null,
schema: [],
supported: CodePathAnalyzer != null,
},
create() {
return visitor
},
}
-170
View File
@@ -1,170 +0,0 @@
/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const path = require("path")
const getConvertPath = require("../util/get-convert-path")
const getPackageJson = require("../util/get-package-json")
const NODE_SHEBANG = "#!/usr/bin/env node\n"
const SHEBANG_PATTERN = /^(#!.+?)?(\r)?\n/u
const NODE_SHEBANG_PATTERN = /#!\/usr\/bin\/env node(?: [^\r\n]+?)?\n/u
function simulateNodeResolutionAlgorithm(filePath, binField) {
const possibilities = [filePath]
let newFilePath = filePath.replace(/\.js$/u, "")
possibilities.push(newFilePath)
newFilePath = newFilePath.replace(/[/\\]index$/u, "")
possibilities.push(newFilePath)
return possibilities.includes(binField)
}
/**
* Checks whether or not a given path is a `bin` file.
*
* @param {string} filePath - A file path to check.
* @param {string|object|undefined} binField - A value of the `bin` field of `package.json`.
* @param {string} basedir - A directory path that `package.json` exists.
* @returns {boolean} `true` if the file is a `bin` file.
*/
function isBinFile(filePath, binField, basedir) {
if (!binField) {
return false
}
if (typeof binField === "string") {
return simulateNodeResolutionAlgorithm(
filePath,
path.resolve(basedir, binField)
)
}
return Object.keys(binField).some(key =>
simulateNodeResolutionAlgorithm(
filePath,
path.resolve(basedir, binField[key])
)
)
}
/**
* Gets the shebang line (includes a line ending) from a given code.
*
* @param {SourceCode} sourceCode - A source code object to check.
* @returns {{length: number, bom: boolean, shebang: string, cr: boolean}}
* shebang's information.
* `retv.shebang` is an empty string if shebang doesn't exist.
*/
function getShebangInfo(sourceCode) {
const m = SHEBANG_PATTERN.exec(sourceCode.text)
return {
bom: sourceCode.hasBOM,
cr: Boolean(m && m[2]),
length: (m && m[0].length) || 0,
shebang: (m && m[1] && `${m[1]}\n`) || "",
}
}
module.exports = {
meta: {
docs: {
description: "suggest correct usage of shebang",
category: "Possible Errors",
recommended: true,
url:
"https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/shebang.md",
},
type: "problem",
fixable: "code",
schema: [
{
type: "object",
properties: {
//
convertPath: getConvertPath.schema,
},
additionalProperties: false,
},
],
},
create(context) {
const sourceCode = context.getSourceCode()
let filePath = context.getFilename()
if (filePath === "<input>") {
return {}
}
filePath = path.resolve(filePath)
const p = getPackageJson(filePath)
if (!p) {
return {}
}
const basedir = path.dirname(p.filePath)
filePath = path.join(
basedir,
getConvertPath(context)(
path.relative(basedir, filePath).replace(/\\/gu, "/")
)
)
const needsShebang = isBinFile(filePath, p.bin, basedir)
const info = getShebangInfo(sourceCode)
return {
Program(node) {
if (
needsShebang
? NODE_SHEBANG_PATTERN.test(info.shebang)
: !info.shebang
) {
// Good the shebang target.
// Checks BOM and \r.
if (needsShebang && info.bom) {
context.report({
node,
message: "This file must not have Unicode BOM.",
fix(fixer) {
return fixer.removeRange([-1, 0])
},
})
}
if (needsShebang && info.cr) {
context.report({
node,
message:
"This file must have Unix linebreaks (LF).",
fix(fixer) {
const index = sourceCode.text.indexOf("\r")
return fixer.removeRange([index, index + 1])
},
})
}
} else if (needsShebang) {
// Shebang is lacking.
context.report({
node,
message:
'This file needs shebang "#!/usr/bin/env node".',
fix(fixer) {
return fixer.replaceTextRange(
[-1, info.length],
NODE_SHEBANG
)
},
})
} else {
// Shebang is extra.
context.report({
node,
message: "This file needs no shebang.",
fix(fixer) {
return fixer.removeRange([0, info.length])
},
})
}
},
}
},
}
-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)
},
}
}
-1
View File
@@ -1 +0,0 @@
../semver/bin/semver.js
-70
View File
@@ -1,70 +0,0 @@
# changes log
## 6.2.0
* Coerce numbers to strings when passed to semver.coerce()
* Add `rtl` option to coerce from right to left
## 6.1.3
* Handle X-ranges properly in includePrerelease mode
## 6.1.2
* Do not throw when testing invalid version strings
## 6.1.1
* Add options support for semver.coerce()
* Handle undefined version passed to Range.test
## 6.1.0
* Add semver.compareBuild function
* Support `*` in semver.intersects
## 6.0
* Fix `intersects` logic.
This is technically a bug fix, but since it is also a change to behavior
that may require users updating their code, it is marked as a major
version increment.
## 5.7
* Add `minVersion` method
## 5.6
* Move boolean `loose` param to an options object, with
backwards-compatibility protection.
* Add ability to opt out of special prerelease version handling with
the `includePrerelease` option flag.
## 5.5
* Add version coercion capabilities
## 5.4
* Add intersection checking
## 5.3
* Add `minSatisfying` method
## 5.2
* Add `prerelease(v)` that returns prerelease components
## 5.1
* Add Backus-Naur for ranges
* Remove excessively cute inspection methods
## 5.0
* Remove AMD/Browserified build artifacts
* Fix ltr and gtr when using the `*` range
* Fix for range `*` with a prerelease identifier
-15
View File
@@ -1,15 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-443
View File
@@ -1,443 +0,0 @@
semver(1) -- The semantic versioner for npm
===========================================
## Install
```bash
npm install semver
````
## Usage
As a node module:
```js
const semver = require('semver')
semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
semver.clean(' =v1.2.3 ') // '1.2.3'
semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
semver.minVersion('>=1.0.0') // '1.0.0'
semver.valid(semver.coerce('v2')) // '2.0.0'
semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7'
```
As a command-line utility:
```
$ semver -h
A JavaScript implementation of the https://semver.org/ specification
Copyright Isaac Z. Schlueter
Usage: semver [options] <version> [<version> [...]]
Prints valid versions sorted by SemVer precedence
Options:
-r --range <range>
Print versions that match the specified range.
-i --increment [<level>]
Increment a version by the specified level. Level can
be one of: major, minor, patch, premajor, preminor,
prepatch, or prerelease. Default level is 'patch'.
Only one version may be specified.
--preid <identifier>
Identifier to be used to prefix premajor, preminor,
prepatch or prerelease version increments.
-l --loose
Interpret versions and ranges loosely
-p --include-prerelease
Always include prerelease versions in range matching
-c --coerce
Coerce a string into SemVer if possible
(does not imply --loose)
--rtl
Coerce version strings right to left
--ltr
Coerce version strings left to right (default)
Program exits successfully if any valid version satisfies
all supplied ranges, and prints all satisfying versions.
If no satisfying versions are found, then exits failure.
Versions are printed in ascending order, so supplying
multiple versions to the utility will just sort them.
```
## Versions
A "version" is described by the `v2.0.0` specification found at
<https://semver.org/>.
A leading `"="` or `"v"` character is stripped off and ignored.
## Ranges
A `version range` is a set of `comparators` which specify versions
that satisfy the range.
A `comparator` is composed of an `operator` and a `version`. The set
of primitive `operators` is:
* `<` Less than
* `<=` Less than or equal to
* `>` Greater than
* `>=` Greater than or equal to
* `=` Equal. If no operator is specified, then equality is assumed,
so this operator is optional, but MAY be included.
For example, the comparator `>=1.2.7` would match the versions
`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
or `1.1.0`.
Comparators can be joined by whitespace to form a `comparator set`,
which is satisfied by the **intersection** of all of the comparators
it includes.
A range is composed of one or more comparator sets, joined by `||`. A
version matches a range if and only if every comparator in at least
one of the `||`-separated comparator sets is satisfied by the version.
For example, the range `>=1.2.7 <1.3.0` would match the versions
`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
or `1.1.0`.
The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
### Prerelease Tags
If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
it will only be allowed to satisfy comparator sets if at least one
comparator with the same `[major, minor, patch]` tuple also has a
prerelease tag.
For example, the range `>1.2.3-alpha.3` would be allowed to match the
version `1.2.3-alpha.7`, but it would *not* be satisfied by
`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
than" `1.2.3-alpha.3` according to the SemVer sort rules. The version
range only accepts prerelease tags on the `1.2.3` version. The
version `3.4.5` *would* satisfy the range, because it does not have a
prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
The purpose for this behavior is twofold. First, prerelease versions
frequently are updated very quickly, and contain many breaking changes
that are (by the author's design) not yet fit for public consumption.
Therefore, by default, they are excluded from range matching
semantics.
Second, a user who has opted into using a prerelease version has
clearly indicated the intent to use *that specific* set of
alpha/beta/rc versions. By including a prerelease tag in the range,
the user is indicating that they are aware of the risk. However, it
is still not appropriate to assume that they have opted into taking a
similar risk on the *next* set of prerelease versions.
Note that this behavior can be suppressed (treating all prerelease
versions as if they were normal versions, for the purpose of range
matching) by setting the `includePrerelease` flag on the options
object to any
[functions](https://github.com/npm/node-semver#functions) that do
range matching.
#### Prerelease Identifiers
The method `.inc` takes an additional `identifier` string argument that
will append the value of the string as a prerelease identifier:
```javascript
semver.inc('1.2.3', 'prerelease', 'beta')
// '1.2.4-beta.0'
```
command-line example:
```bash
$ semver 1.2.3 -i prerelease --preid beta
1.2.4-beta.0
```
Which then can be used to increment further:
```bash
$ semver 1.2.4-beta.0 -i prerelease
1.2.4-beta.1
```
### Advanced Range Syntax
Advanced range syntax desugars to primitive comparators in
deterministic ways.
Advanced ranges may be combined in the same way as primitive
comparators using white space or `||`.
#### Hyphen Ranges `X.Y.Z - A.B.C`
Specifies an inclusive set.
* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
If a partial version is provided as the first version in the inclusive
range, then the missing pieces are replaced with zeroes.
* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
If a partial version is provided as the second version in the
inclusive range, then all versions that start with the supplied parts
of the tuple are accepted, but nothing that would be greater than the
provided tuple parts.
* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
Any of `X`, `x`, or `*` may be used to "stand in" for one of the
numeric values in the `[major, minor, patch]` tuple.
* `*` := `>=0.0.0` (Any version satisfies)
* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
A partial version range is treated as an X-Range, so the special
character is in fact optional.
* `""` (empty string) := `*` := `>=0.0.0`
* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
#### Tilde Ranges `~1.2.3` `~1.2` `~1`
Allows patch-level changes if a minor version is specified on the
comparator. Allows minor-level changes if not.
* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
the `1.2.3` version will be allowed, if they are greater than or
equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
`1.2.4-beta.2` would not, because it is a prerelease of a
different `[major, minor, patch]` tuple.
#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
Allows changes that do not modify the left-most non-zero element in the
`[major, minor, patch]` tuple. In other words, this allows patch and
minor updates for versions `1.0.0` and above, patch updates for
versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
Many authors treat a `0.x` version as if the `x` were the major
"breaking-change" indicator.
Caret ranges are ideal when an author may make breaking changes
between `0.2.4` and `0.3.0` releases, which is a common practice.
However, it presumes that there will *not* be breaking changes between
`0.2.4` and `0.2.5`. It allows for changes that are presumed to be
additive (but non-breaking), according to commonly observed practices.
* `^1.2.3` := `>=1.2.3 <2.0.0`
* `^0.2.3` := `>=0.2.3 <0.3.0`
* `^0.0.3` := `>=0.0.3 <0.0.4`
* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
the `1.2.3` version will be allowed, if they are greater than or
equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
`1.2.4-beta.2` would not, because it is a prerelease of a
different `[major, minor, patch]` tuple.
* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the
`0.0.3` version *only* will be allowed, if they are greater than or
equal to `beta`. So, `0.0.3-pr.2` would be allowed.
When parsing caret ranges, a missing `patch` value desugars to the
number `0`, but will allow flexibility within that value, even if the
major and minor versions are both `0`.
* `^1.2.x` := `>=1.2.0 <2.0.0`
* `^0.0.x` := `>=0.0.0 <0.1.0`
* `^0.0` := `>=0.0.0 <0.1.0`
A missing `minor` and `patch` values will desugar to zero, but also
allow flexibility within those values, even if the major version is
zero.
* `^1.x` := `>=1.0.0 <2.0.0`
* `^0.x` := `>=0.0.0 <1.0.0`
### Range Grammar
Putting all this together, here is a Backus-Naur grammar for ranges,
for the benefit of parser authors:
```bnf
range-set ::= range ( logical-or range ) *
logical-or ::= ( ' ' ) * '||' ( ' ' ) *
range ::= hyphen | simple ( ' ' simple ) * | ''
hyphen ::= partial ' - ' partial
simple ::= primitive | partial | tilde | caret
primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
xr ::= 'x' | 'X' | '*' | nr
nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
tilde ::= '~' partial
caret ::= '^' partial
qualifier ::= ( '-' pre )? ( '+' build )?
pre ::= parts
build ::= parts
parts ::= part ( '.' part ) *
part ::= nr | [-0-9A-Za-z]+
```
## Functions
All methods and classes take a final `options` object argument. All
options in this object are `false` by default. The options supported
are:
- `loose` Be more forgiving about not-quite-valid semver strings.
(Any resulting output will always be 100% strict compliant, of
course.) For backwards compatibility reasons, if the `options`
argument is a boolean value instead of an object, it is interpreted
to be the `loose` param.
- `includePrerelease` Set to suppress the [default
behavior](https://github.com/npm/node-semver#prerelease-tags) of
excluding prerelease tagged versions from ranges unless they are
explicitly opted into.
Strict-mode Comparators and Ranges will be strict about the SemVer
strings that they parse.
* `valid(v)`: Return the parsed version, or null if it's not valid.
* `inc(v, release)`: Return the version incremented by the release
type (`major`, `premajor`, `minor`, `preminor`, `patch`,
`prepatch`, or `prerelease`), or null if it's not valid
* `premajor` in one call will bump the version up to the next major
version and down to a prerelease of that major version.
`preminor`, and `prepatch` work the same way.
* If called from a non-prerelease version, the `prerelease` will work the
same as `prepatch`. It increments the patch version, then makes a
prerelease. If the input version is already a prerelease it simply
increments it.
* `prerelease(v)`: Returns an array of prerelease components, or null
if none exist. Example: `prerelease('1.2.3-alpha.1') -> ['alpha', 1]`
* `major(v)`: Return the major version number.
* `minor(v)`: Return the minor version number.
* `patch(v)`: Return the patch version number.
* `intersects(r1, r2, loose)`: Return true if the two supplied ranges
or comparators intersect.
* `parse(v)`: Attempt to parse a string as a semantic version, returning either
a `SemVer` object or `null`.
### Comparison
* `gt(v1, v2)`: `v1 > v2`
* `gte(v1, v2)`: `v1 >= v2`
* `lt(v1, v2)`: `v1 < v2`
* `lte(v1, v2)`: `v1 <= v2`
* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,
even if they're not the exact same string. You already know how to
compare strings.
* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.
* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call
the corresponding function above. `"==="` and `"!=="` do simple
string comparison, but are included for completeness. Throws if an
invalid comparison string is provided.
* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if
`v2` is greater. Sorts in ascending order if passed to `Array.sort()`.
* `rcompare(v1, v2)`: The reverse of compare. Sorts an array of versions
in descending order when passed to `Array.sort()`.
* `compareBuild(v1, v2)`: The same as `compare` but considers `build` when two versions
are equal. Sorts in ascending order if passed to `Array.sort()`.
`v2` is greater. Sorts in ascending order if passed to `Array.sort()`.
* `diff(v1, v2)`: Returns difference between two versions by the release type
(`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),
or null if the versions are the same.
### Comparators
* `intersects(comparator)`: Return true if the comparators intersect
### Ranges
* `validRange(range)`: Return the valid range or null if it's not valid
* `satisfies(version, range)`: Return true if the version satisfies the
range.
* `maxSatisfying(versions, range)`: Return the highest version in the list
that satisfies the range, or `null` if none of them do.
* `minSatisfying(versions, range)`: Return the lowest version in the list
that satisfies the range, or `null` if none of them do.
* `minVersion(range)`: Return the lowest version that can possibly match
the given range.
* `gtr(version, range)`: Return `true` if version is greater than all the
versions possible in the range.
* `ltr(version, range)`: Return `true` if version is less than all the
versions possible in the range.
* `outside(version, range, hilo)`: Return true if the version is outside
the bounds of the range in either the high or low direction. The
`hilo` argument must be either the string `'>'` or `'<'`. (This is
the function called by `gtr` and `ltr`.)
* `intersects(range)`: Return true if any of the ranges comparators intersect
Note that, since ranges may be non-contiguous, a version might not be
greater than a range, less than a range, *or* satisfy a range! For
example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`
until `2.0.0`, so the version `1.2.10` would not be greater than the
range (because `2.0.1` satisfies, which is higher), nor less than the
range (since `1.2.8` satisfies, which is lower), and it also does not
satisfy the range.
If you want to know if a version satisfies or does not satisfy a
range, use the `satisfies(version, range)` function.
### Coercion
* `coerce(version, options)`: Coerces a string to semver if possible
This aims to provide a very forgiving translation of a non-semver string to
semver. It looks for the first digit in a string, and consumes all
remaining characters which satisfy at least a partial semver (e.g., `1`,
`1.2`, `1.2.3`) up to the max permitted length (256 characters). Longer
versions are simply truncated (`4.6.3.9.2-alpha2` becomes `4.6.3`). All
surrounding text is simply ignored (`v3.4 replaces v3.3.1` becomes
`3.4.0`). Only text which lacks digits will fail coercion (`version one`
is not valid). The maximum length for any semver component considered for
coercion is 16 characters; longer components will be ignored
(`10000000000000000.4.7.4` becomes `4.7.4`). The maximum value for any
semver component is `Integer.MAX_SAFE_INTEGER || (2**53 - 1)`; higher value
components are invalid (`9999999999999999.4.7.4` is likely invalid).
If the `options.rtl` flag is set, then `coerce` will return the right-most
coercible tuple that does not share an ending index with a longer coercible
tuple. For example, `1.2.3.4` will return `2.3.4` in rtl mode, not
`4.0.0`. `1.2.3/4` will return `4.0.0`, because the `4` is not a part of
any other overlapping SemVer tuple.
### Clean
* `clean(version)`: Clean a string to be a valid semver if possible
This will return a cleaned and trimmed semver version. If the provided version is not valid a null will be returned. This does not work for ranges.
ex.
* `s.clean(' = v 2.1.5foo')`: `null`
* `s.clean(' = v 2.1.5foo', { loose: true })`: `'2.1.5-foo'`
* `s.clean(' = v 2.1.5-foo')`: `null`
* `s.clean(' = v 2.1.5-foo', { loose: true })`: `'2.1.5-foo'`
* `s.clean('=v2.1.5')`: `'2.1.5'`
* `s.clean(' =v2.1.5')`: `2.1.5`
* `s.clean(' 2.1.5 ')`: `'2.1.5'`
* `s.clean('~1.0.0')`: `null`
-174
View File
@@ -1,174 +0,0 @@
#!/usr/bin/env node
// Standalone semver comparison program.
// Exits successfully and prints matching version(s) if
// any supplied version is valid and passes all tests.
var argv = process.argv.slice(2)
var versions = []
var range = []
var inc = null
var version = require('../package.json').version
var loose = false
var includePrerelease = false
var coerce = false
var rtl = false
var identifier
var semver = require('../semver')
var reverse = false
var options = {}
main()
function main () {
if (!argv.length) return help()
while (argv.length) {
var a = argv.shift()
var indexOfEqualSign = a.indexOf('=')
if (indexOfEqualSign !== -1) {
a = a.slice(0, indexOfEqualSign)
argv.unshift(a.slice(indexOfEqualSign + 1))
}
switch (a) {
case '-rv': case '-rev': case '--rev': case '--reverse':
reverse = true
break
case '-l': case '--loose':
loose = true
break
case '-p': case '--include-prerelease':
includePrerelease = true
break
case '-v': case '--version':
versions.push(argv.shift())
break
case '-i': case '--inc': case '--increment':
switch (argv[0]) {
case 'major': case 'minor': case 'patch': case 'prerelease':
case 'premajor': case 'preminor': case 'prepatch':
inc = argv.shift()
break
default:
inc = 'patch'
break
}
break
case '--preid':
identifier = argv.shift()
break
case '-r': case '--range':
range.push(argv.shift())
break
case '-c': case '--coerce':
coerce = true
break
case '--rtl':
rtl = true
break
case '--ltr':
rtl = false
break
case '-h': case '--help': case '-?':
return help()
default:
versions.push(a)
break
}
}
var options = { loose: loose, includePrerelease: includePrerelease, rtl: rtl }
versions = versions.map(function (v) {
return coerce ? (semver.coerce(v, options) || { version: v }).version : v
}).filter(function (v) {
return semver.valid(v)
})
if (!versions.length) return fail()
if (inc && (versions.length !== 1 || range.length)) { return failInc() }
for (var i = 0, l = range.length; i < l; i++) {
versions = versions.filter(function (v) {
return semver.satisfies(v, range[i], options)
})
if (!versions.length) return fail()
}
return success(versions)
}
function failInc () {
console.error('--inc can only be used on a single version with no range')
fail()
}
function fail () { process.exit(1) }
function success () {
var compare = reverse ? 'rcompare' : 'compare'
versions.sort(function (a, b) {
return semver[compare](a, b, options)
}).map(function (v) {
return semver.clean(v, options)
}).map(function (v) {
return inc ? semver.inc(v, inc, options, identifier) : v
}).forEach(function (v, i, _) { console.log(v) })
}
function help () {
console.log(['SemVer ' + version,
'',
'A JavaScript implementation of the https://semver.org/ specification',
'Copyright Isaac Z. Schlueter',
'',
'Usage: semver [options] <version> [<version> [...]]',
'Prints valid versions sorted by SemVer precedence',
'',
'Options:',
'-r --range <range>',
' Print versions that match the specified range.',
'',
'-i --increment [<level>]',
' Increment a version by the specified level. Level can',
' be one of: major, minor, patch, premajor, preminor,',
" prepatch, or prerelease. Default level is 'patch'.",
' Only one version may be specified.',
'',
'--preid <identifier>',
' Identifier to be used to prefix premajor, preminor,',
' prepatch or prerelease version increments.',
'',
'-l --loose',
' Interpret versions and ranges loosely',
'',
'-p --include-prerelease',
' Always include prerelease versions in range matching',
'',
'-c --coerce',
' Coerce a string into SemVer if possible',
' (does not imply --loose)',
'',
'--rtl',
' Coerce version strings right to left',
'',
'--ltr',
' Coerce version strings left to right (default)',
'',
'Program exits successfully if any valid version satisfies',
'all supplied ranges, and prints all satisfying versions.',
'',
'If no satisfying versions are found, then exits failure.',
'',
'Versions are printed in ascending order, so supplying',
'multiple versions to the utility will just sort them.'
].join('\n'))
}
-64
View File
@@ -1,64 +0,0 @@
{
"_args": [
[
"semver@6.3.0",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
]
],
"_development": true,
"_from": "semver@6.3.0",
"_id": "semver@6.3.0",
"_inBundle": false,
"_integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"_location": "/eslint-plugin-node/semver",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "semver@6.3.0",
"name": "semver",
"escapedName": "semver",
"rawSpec": "6.3.0",
"saveSpec": null,
"fetchSpec": "6.3.0"
},
"_requiredBy": [
"/eslint-plugin-node"
],
"_resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"_spec": "6.3.0",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"bin": {
"semver": "bin/semver.js"
},
"bugs": {
"url": "https://github.com/npm/node-semver/issues"
},
"description": "The semantic version parser used by npm.",
"devDependencies": {
"tap": "^14.3.1"
},
"files": [
"bin",
"range.bnf",
"semver.js"
],
"homepage": "https://github.com/npm/node-semver#readme",
"license": "ISC",
"main": "semver.js",
"name": "semver",
"repository": {
"type": "git",
"url": "git+https://github.com/npm/node-semver.git"
},
"scripts": {
"postpublish": "git push origin --follow-tags",
"postversion": "npm publish",
"preversion": "npm test",
"test": "tap"
},
"tap": {
"check-coverage": true
},
"version": "6.3.0"
}
-16
View File
@@ -1,16 +0,0 @@
range-set ::= range ( logical-or range ) *
logical-or ::= ( ' ' ) * '||' ( ' ' ) *
range ::= hyphen | simple ( ' ' simple ) * | ''
hyphen ::= partial ' - ' partial
simple ::= primitive | partial | tilde | caret
primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
xr ::= 'x' | 'X' | '*' | nr
nr ::= '0' | [1-9] ( [0-9] ) *
tilde ::= '~' partial
caret ::= '^' partial
qualifier ::= ( '-' pre )? ( '+' build )?
pre ::= parts
build ::= parts
parts ::= part ( '.' part ) *
part ::= nr | [-0-9A-Za-z]+
File diff suppressed because it is too large Load Diff
-106
View File
@@ -1,106 +0,0 @@
{
"_args": [
[
"eslint-plugin-node@11.1.0",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
]
],
"_development": true,
"_from": "eslint-plugin-node@11.1.0",
"_id": "eslint-plugin-node@11.1.0",
"_inBundle": false,
"_integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==",
"_location": "/eslint-plugin-node",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "eslint-plugin-node@11.1.0",
"name": "eslint-plugin-node",
"escapedName": "eslint-plugin-node",
"rawSpec": "11.1.0",
"saveSpec": null,
"fetchSpec": "11.1.0"
},
"_requiredBy": [
"/@nuxtjs/eslint-config"
],
"_resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
"_spec": "11.1.0",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"author": {
"name": "Toru Nagashima"
},
"bugs": {
"url": "https://github.com/mysticatea/eslint-plugin-node/issues"
},
"dependencies": {
"eslint-plugin-es": "^3.0.0",
"eslint-utils": "^2.0.0",
"ignore": "^5.1.1",
"minimatch": "^3.0.4",
"resolve": "^1.10.1",
"semver": "^6.1.0"
},
"description": "Additional ESLint's rules for Node.js",
"devDependencies": {
"@mysticatea/eslint-plugin": "^10.0.3",
"codecov": "^3.3.0",
"eslint": "^6.3.0",
"eslint-plugin-node": "file:.",
"fast-glob": "^2.2.6",
"globals": "^11.12.0",
"mocha": "^6.1.4",
"nyc": "^14.0.0",
"opener": "^1.5.1",
"punycode": "^2.1.1",
"rimraf": "^2.6.3"
},
"engines": {
"node": ">=8.10.0"
},
"files": [
"lib"
],
"homepage": "https://github.com/mysticatea/eslint-plugin-node#readme",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"node",
"nodejs",
"ecmascript",
"shebang",
"file",
"path",
"import",
"require"
],
"license": "MIT",
"main": "lib/index.js",
"name": "eslint-plugin-node",
"peerDependencies": {
"eslint": ">=5.16.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mysticatea/eslint-plugin-node.git"
},
"scripts": {
"build": "node scripts/update",
"clean": "rimraf .nyc_output coverage",
"codecov": "nyc report --reporter text-lcov | codecov --pipe --disable=gcov -t $CODECOV_TOKEN",
"coverage": "opener ./coverage/lcov-report/index.html",
"lint": "eslint lib scripts tests/lib .eslintrc.js",
"new": "node scripts/new-rule",
"postversion": "git push && git push --tags",
"pretest": "npm run -s lint",
"preversion": "npm t && npm run -s build",
"test": "nyc npm run -s test:_mocha",
"test:_mocha": "_mocha \"tests/lib/**/*.js\" --reporter progress --timeout 4000",
"test:ci": "nyc npm run -s test:_mocha",
"version": "eslint lib/rules --fix && git add lib/rules",
"watch": "npm run test:_mocha -- --watch --growl"
},
"version": "11.1.0"
}