Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-unicorn

Package Overview
Dependencies
Maintainers
1
Versions
107
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-unicorn - npm Package Compare versions

Comparing version 26.0.1 to 27.0.0

rules/no-array-for-each.js

3

index.js

@@ -58,2 +58,4 @@ 'use strict';

'unicorn/no-array-callback-reference': 'error',
'unicorn/no-array-for-each': 'error',
'unicorn/no-array-push-push': 'error',
'unicorn/no-array-reduce': 'error',

@@ -73,2 +75,3 @@ 'unicorn/no-console-spaces': 'error',

'unicorn/no-process-exit': 'error',
'unicorn/no-this-assignment': 'error',
'unicorn/no-unreadable-array-destructuring': 'error',

@@ -75,0 +78,0 @@ 'unicorn/no-unsafe-regex': 'off',

11

package.json
{
"name": "eslint-plugin-unicorn",
"version": "26.0.1",
"version": "27.0.0",
"description": "Various awesome ESLint rules",

@@ -19,3 +19,3 @@ "license": "MIT",

"create-rule": "node ./scripts/create-rule.js",
"lint": "node ./test/lint/lint.js",
"run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.js",
"integration": "node ./test/integration/test.js",

@@ -41,3 +41,2 @@ "smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js"

"clean-regexp": "^1.0.0",
"eslint-ast-utils": "^1.1.0",
"eslint-template-visitor": "^2.2.2",

@@ -49,3 +48,3 @@ "eslint-utils": "^2.1.0",

"read-pkg-up": "^7.0.1",
"regexp-tree": "^0.1.21",
"regexp-tree": "^0.1.22",
"reserved-words": "^0.1.2",

@@ -58,2 +57,4 @@ "safe-regex": "^2.1.1",

"@babel/code-frame": "7.12.11",
"@babel/core": "7.12.10",
"@babel/eslint-parser": "7.12.1",
"@lubien/fixture-beta-package": "^1.0.0-beta.1",

@@ -105,3 +106,3 @@ "@typescript-eslint/parser": "^4.12.0",

"ignores": [
"test/integration/{fixtures,unicorn}/**",
"test/integration/{fixtures,fixtures-local}/**",
".cache-eslint-remote-tester",

@@ -108,0 +109,0 @@ "eslint-remote-tester-results"

@@ -52,2 +52,4 @@ # eslint-plugin-unicorn [![Coverage Status](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/eslint-plugin-unicorn/branch/master)

"unicorn/no-array-callback-reference": "error",
"unicorn/no-array-for-each": "error",
"unicorn/no-array-push-push": "error",
"unicorn/no-array-reduce": "error",

@@ -67,2 +69,3 @@ "unicorn/no-console-spaces": "error",

"unicorn/no-process-exit": "error",
"unicorn/no-this-assignment": "error",
"unicorn/no-unreadable-array-destructuring": "error",

@@ -130,2 +133,4 @@ "unicorn/no-unsafe-regex": "off",

- [no-array-callback-reference](docs/rules/no-array-callback-reference.md) - Prevent passing a function reference directly to iterator methods.
- [no-array-for-each](docs/rules/no-array-for-each.md) - Prefer `for…of` over `Array#forEach(…)`. *(partly fixable)*
- [no-array-push-push](docs/rules/no-array-push-push.md) - Enforce combining multiple `Array#push()` into one call. *(partly fixable)*
- [no-array-reduce](docs/rules/no-array-reduce.md) - Disallow `Array#reduce()` and `Array#reduceRight()`.

@@ -140,7 +145,8 @@ - [no-console-spaces](docs/rules/no-console-spaces.md) - Do not use leading/trailing space between `console.log` parameters. *(fixable)*

- [no-new-array](docs/rules/no-new-array.md) - Disallow `new Array()`. *(partly fixable)*
- [no-new-buffer](docs/rules/no-new-buffer.md) - Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. *(fixable)*
- [no-new-buffer](docs/rules/no-new-buffer.md) - Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. *(partly fixable)*
- [no-null](docs/rules/no-null.md) - Disallow the use of the `null` literal.
- [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) - Disallow the use of objects as default parameters.
- [no-process-exit](docs/rules/no-process-exit.md) - Disallow `process.exit()`.
- [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) - Disallow unreadable array destructuring.
- [no-this-assignment](docs/rules/no-this-assignment.md) - Disallow assigning `this` to a variable.
- [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) - Disallow unreadable array destructuring. *(partly fixable)*
- [no-unsafe-regex](docs/rules/no-unsafe-regex.md) - Disallow unsafe regular expressions.

@@ -174,3 +180,3 @@ - [no-unused-properties](docs/rules/no-unused-properties.md) - Disallow unused object properties.

- [prefer-set-has](docs/rules/prefer-set-has.md) - Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. *(fixable)*
- [prefer-spread](docs/rules/prefer-spread.md) - Prefer the spread operator over `Array.from()`. *(fixable)*
- [prefer-spread](docs/rules/prefer-spread.md) - Prefer the spread operator over `Array.from()` and `Array#concat()`. *(partly fixable)*
- [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) - Prefer `String#replaceAll()` over regex searches with the global flag. *(fixable)*

@@ -177,0 +183,0 @@ - [prefer-string-slice](docs/rules/prefer-string-slice.md) - Prefer `String#slice()` over `String#substr()` and `String#substring()`. *(partly fixable)*

@@ -5,2 +5,3 @@ 'use strict';

const isShadowed = require('./utils/is-shadowed');
const switchNewExpressionToCallExpression = require('./utils/switch-new-expression-to-call-expression');

@@ -16,2 +17,4 @@ const messages = {

const create = context => {
const sourceCode = context.getSourceCode();
return {

@@ -42,4 +45,4 @@ CallExpression: node => {

NewExpression: node => {
const {callee, range} = node;
const {name, range: calleeRange} = callee;
const {callee} = node;
const {name} = callee;

@@ -54,6 +57,5 @@ if (disallowNew.has(name) && !isShadowed(context.getScope(), callee)) {

if (name !== 'String' && name !== 'Boolean' && name !== 'Number') {
problem.fix = fixer => fixer.removeRange([
range[0],
calleeRange[0]
]);
problem.fix = function * (fixer) {
yield * switchNewExpressionToCallExpression(node, sourceCode, fixer);
};
}

@@ -60,0 +62,0 @@

@@ -28,3 +28,7 @@ 'use strict';

['flatMap'],
['forEach'],
[
'forEach', {
returnsUndefined: true
}
],
['map'],

@@ -62,2 +66,3 @@ [

extraSelector: '',
returnsUndefined: false,
...options

@@ -110,3 +115,3 @@ };

const {parameters, minParameters} = options;
const {parameters, minParameters, returnsUndefined} = options;
for (let parameterLength = minParameters; parameterLength <= parameters.length; parameterLength++) {

@@ -130,3 +135,5 @@ const suggestionParameters = parameters.slice(0, parameterLength).join(', ');

node,
`(${suggestionParameters}) => ${nodeText}(${suggestionParameters})`
returnsUndefined ?
`(${suggestionParameters}) => { ${nodeText}(${suggestionParameters}); }` :
`(${suggestionParameters}) => ${nodeText}(${suggestionParameters})`
);

@@ -133,0 +140,0 @@ }

'use strict';
const {isParenthesized, isOpeningParenToken, isClosingParenToken} = require('eslint-utils');
const getDocumentationUrl = require('./utils/get-documentation-url');
const replaceNodeOrTokenAndSpacesBefore = require('./utils/replace-node-or-token-and-spaces-before');
const isInstanceofToken = token => token.value === 'instanceof' && token.type === 'Keyword';
const MESSAGE_ID = 'no-instanceof-array';

@@ -22,6 +26,19 @@ const messages = {

messageId: MESSAGE_ID,
fix: fixer => fixer.replaceText(
node,
`Array.isArray(${sourceCode.getText(node.left)})`
)
* fix(fixer) {
const {left, right} = node;
let leftStartNodeOrToken = left;
let leftEndNodeOrToken = left;
if (isParenthesized(left, sourceCode)) {
leftStartNodeOrToken = sourceCode.getTokenBefore(left, isOpeningParenToken);
leftEndNodeOrToken = sourceCode.getTokenAfter(left, isClosingParenToken);
}
yield fixer.insertTextBefore(leftStartNodeOrToken, 'Array.isArray(');
yield fixer.insertTextAfter(leftEndNodeOrToken, ')');
const instanceofToken = sourceCode.getTokenAfter(left, isInstanceofToken);
yield * replaceNodeOrTokenAndSpacesBefore(instanceofToken, '', fixer, sourceCode);
yield * replaceNodeOrTokenAndSpacesBefore(right, '', fixer, sourceCode);
}
})

@@ -28,0 +45,0 @@ };

'use strict';
const {getStaticValue} = require('eslint-utils');
const getDocumentationUrl = require('./utils/get-documentation-url');
const switchNewExpressionToCallExpression = require('./utils/switch-new-expression-to-call-expression');
const MESSAGE_ID = 'no-new-buffer';
const ERROR = 'error';
const ERROR_UNKNOWN = 'error-unknown';
const SUGGESTION = 'suggestion';
const messages = {
[MESSAGE_ID]: '`new Buffer()` is deprecated, use `Buffer.{{method}}()` instead.'
[ERROR]: '`new Buffer()` is deprecated, use `Buffer.{{method}}()` instead.',
[ERROR_UNKNOWN]: '`new Buffer()` is deprecated, use `Buffer.alloc()` or `Buffer.from()` instead.',
[SUGGESTION]: 'Switch to `Buffer.{{method}}()`.'
};
const inferMethod = arguments_ => {
if (arguments_.length > 0) {
const [firstArgument] = arguments_;
const inferMethod = (bufferArguments, scope) => {
if (bufferArguments.length !== 1) {
return 'from';
}
const [firstArgument] = bufferArguments;
if (firstArgument.type === 'SpreadElement') {
return;
}
if (firstArgument.type === 'ArrayExpression' || firstArgument.type === 'TemplateLiteral') {
return 'from';
}
const staticResult = getStaticValue(firstArgument, scope);
if (staticResult) {
const {value} = staticResult;
if (typeof value === 'number') {
return 'alloc';
}
if (
firstArgument.type === 'Literal' &&
typeof firstArgument.value === 'number'
typeof value === 'string' ||
Array.isArray(value)
) {
return 'alloc';
return 'from';
}
}
return 'from';
};
function fix(node, sourceCode, method) {
return function * (fixer) {
yield fixer.insertTextAfter(node.callee, `.${method}`);
yield * switchNewExpressionToCallExpression(node, sourceCode, fixer);
};
}
const create = context => {
const sourceCode = context.getSourceCode();
return {
'NewExpression[callee.name="Buffer"]': node => {
const method = inferMethod(node.arguments);
const range = [
node.range[0],
node.callee.range[1]
];
const method = inferMethod(node.arguments, context.getScope());
context.report({
node,
messageId: MESSAGE_ID,
data: {method},
fix: fixer => fixer.replaceTextRange(range, `Buffer.${method}`)
});
if (method) {
context.report({
node,
messageId: ERROR,
data: {method},
fix: fix(node, sourceCode, method)
});
} else {
context.report({
node,
messageId: ERROR_UNKNOWN,
suggest: [
'from',
'alloc'
].map(method => ({
messageId: SUGGESTION,
data: {method},
fix: fix(node, sourceCode, method)
}))
});
}
}

@@ -39,0 +80,0 @@ };

'use strict';
const {isParenthesized} = require('eslint-utils');
const getDocumentationUrl = require('./utils/get-documentation-url');
const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object');

@@ -13,10 +15,49 @@ const MESSAGE_ID = 'no-unreadable-array-destructuring';

const create = context => {
const sourceCode = context.getSourceCode();
return {
'ArrayPattern[elements.length>=3]': node => {
if (node.elements.some((element, index, array) => isCommaFollowedWithComma(element, index, array))) {
context.report({
node,
messageId: MESSAGE_ID
});
'ArrayPattern[elements.length>=3]'(node) {
const {elements, parent} = node;
if (!elements.some((element, index, elements) => isCommaFollowedWithComma(element, index, elements))) {
return;
}
const problem = {
node,
messageId: MESSAGE_ID
};
const nonNullElements = elements.filter(node => node !== null);
if (
parent.type === 'VariableDeclarator' &&
parent.id === node &&
nonNullElements.length === 1
) {
const [element] = nonNullElements;
if (element.type !== 'AssignmentPattern') {
problem.fix = function * (fixer) {
const index = elements.indexOf(element);
const isSlice = element.type === 'RestElement';
const variable = isSlice ? element.argument : element;
yield fixer.replaceText(node, sourceCode.getText(variable));
const code = isSlice ? `.slice(${index})` : `[${index}]`;
const array = parent.init;
if (
!isParenthesized(array, sourceCode) &&
shouldAddParenthesesToMemberExpressionObject(array, sourceCode)
) {
yield fixer.insertTextBefore(array, '(');
yield fixer.insertTextAfter(parent, `)${code}`);
} else {
yield fixer.insertTextAfter(parent, code);
}
};
}
}
context.report(problem);
}

@@ -33,4 +74,5 @@ };

},
messages
messages,
fixable: 'code'
}
};

@@ -121,14 +121,14 @@ 'use strict';

const checkProperties = (objectExpression, references, path = []) => {
objectExpression.properties.forEach(property => {
for (const property of objectExpression.properties) {
const {key} = property;
if (!key) {
return;
continue;
}
if (propertyKeysEqual(key, specialProtoPropertyKey)) {
return;
continue;
}
const nextPath = path.concat(key);
const nextPath = [...path, key];

@@ -191,3 +191,3 @@ const nextReferences = references

checkProperty(property, nextReferences, nextPath);
});
}
};

@@ -220,7 +220,11 @@

const checkVariables = scope => {
scope.variables.forEach(variable => checkVariable(variable));
for (const variable of scope.variables) {
checkVariable(variable);
}
};
const checkChildScopes = scope => {
scope.childScopes.forEach(scope => checkScope(scope));
for (const childScope of scope.childScopes) {
checkScope(childScope);
}
};

@@ -227,0 +231,0 @@

'use strict';
const {defaultsDeep, fromPairs} = require('lodash');
const {fromPairs} = require('lodash');
const getDocumentationUrl = require('./utils/get-documentation-url');

@@ -50,8 +50,3 @@

function format(value, options) {
const {
prefix = '',
data
} = value.match(/^(?<prefix>0[box])?(?<data>.*)$/i).groups;
function format(value, {prefix, data}, options) {
const formatOption = options[prefix.toLowerCase()];

@@ -74,14 +69,40 @@

const defaultOptions = {
hexadecimal: {minimumDigits: 0, groupLength: 2},
binary: {minimumDigits: 0, groupLength: 4},
octal: {minimumDigits: 0, groupLength: 4},
hexadecimal: {minimumDigits: 0, groupLength: 2},
number: {minimumDigits: 5, groupLength: 3}
};
const create = context => {
const rawOptions = defaultsDeep({}, context.options[0], defaultOptions);
const {
onlyIfContainsSeparator,
binary,
octal,
hexadecimal,
number
} = {
onlyIfContainsSeparator: false,
...context.options[0]
};
const options = {
'0b': rawOptions.binary,
'0o': rawOptions.octal,
'0x': rawOptions.hexadecimal,
'': rawOptions.number
'0b': {
onlyIfContainsSeparator,
...defaultOptions.binary,
...binary
},
'0o': {
onlyIfContainsSeparator,
...defaultOptions.octal,
...octal
},
'0x': {
onlyIfContainsSeparator,
...defaultOptions.hexadecimal,
...hexadecimal
},
'': {
onlyIfContainsSeparator,
...defaultOptions.number,
...number
}
};

@@ -106,4 +127,12 @@

const formatted = format(number.replace(/_/g, ''), options) + suffix;
const strippedNumber = number.replace(/_/g, '');
const {prefix = '', data} = strippedNumber.match(/^(?<prefix>0[box])?(?<data>.*)$/i).groups;
const {onlyIfContainsSeparator} = options[prefix.toLowerCase()];
if (onlyIfContainsSeparator && !raw.includes('_')) {
return;
}
const formatted = format(strippedNumber, {prefix, data}, options) + suffix;
if (raw !== formatted) {

@@ -123,2 +152,5 @@ context.report({

properties: {
onlyIfContainsSeparator: {
type: 'boolean'
},
minimumDigits: {

@@ -140,5 +172,11 @@ type: 'integer',

type: 'object',
properties: fromPairs(
Object.entries(defaultOptions).map(([type, options]) => [type, formatOptionsSchema(options)])
),
properties: {
...fromPairs(
Object.entries(defaultOptions).map(([type, options]) => [type, formatOptionsSchema(options)])
),
onlyIfContainsSeparator: {
type: 'boolean',
default: false
}
},
additionalProperties: false

@@ -145,0 +183,0 @@ }];

@@ -70,3 +70,3 @@ 'use strict';

if (node.type === 'Literal') {
return node.value === null || Boolean(node.value.trim());
return node.raw === 'null' || (typeof node.value === 'string' && Boolean(node.value.trim()));
}

@@ -73,0 +73,0 @@

'use strict';
const astUtils = require('eslint-ast-utils');
const getDocumentationUrl = require('./utils/get-documentation-url');
const isLiteralValue = require('./utils/is-literal-value');
const getPropertyName = require('./utils/get-property-name');

@@ -29,3 +29,3 @@ const MESSAGE_ID = 'prefer-reflect-apply';

if (
astUtils.getPropertyName(node.callee) === 'apply' &&
getPropertyName(node.callee) === 'apply' &&
node.arguments.length === 2 &&

@@ -45,5 +45,5 @@ isApplySignature(node.arguments[0], node.arguments[1])

if (
astUtils.getPropertyName(node.callee) === 'call' &&
astUtils.getPropertyName(node.callee.object) === 'apply' &&
astUtils.getPropertyName(node.callee.object.object) === 'prototype' &&
getPropertyName(node.callee) === 'call' &&
getPropertyName(node.callee.object) === 'apply' &&
getPropertyName(node.callee.object.object) === 'prototype' &&
node.callee.object.object.object &&

@@ -50,0 +50,0 @@ node.callee.object.object.object.type === 'Identifier' &&

'use strict';
const {isParenthesized, getStaticValue, isCommaToken} = require('eslint-utils');
const getDocumentationUrl = require('./utils/get-documentation-url');
const methodSelector = require('./utils/method-selector');
const needsSemicolon = require('./utils/needs-semicolon');
const getParentheses = require('./utils/get-parentheses');
const shouldAddParenthesesToSpreadElementArgument = require('./utils/should-add-parentheses-to-spread-element-argument');
const MESSAGE_ID = 'prefer-spread';
const ERROR_ARRAY_FROM = 'array-from';
const ERROR_ARRAY_CONCAT = 'array-concat';
const SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE = 'argument-is-spreadable';
const SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE = 'argument-is-not-spreadable';
const messages = {
[MESSAGE_ID]: 'Prefer the spread operator over `Array.from()`.'
[ERROR_ARRAY_FROM]: 'Prefer the spread operator over `Array.from(…)`.',
[ERROR_ARRAY_CONCAT]: 'Prefer the spread operator over `Array#concat(…)`.',
[SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE]: 'First argument is an `array`.',
[SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE]: 'First argument is not an `array`.'
};
const selector = [
const arrayFromCallSelector = [
methodSelector({

@@ -22,2 +31,191 @@ object: 'Array',

const arrayConcatCallSelector = [
methodSelector({
name: 'concat'
}),
`:not(${
[
'Literal',
'TemplateLiteral'
].map(type => `[callee.object.type="${type}"]`).join(', ')
})`
].join('');
const isArrayLiteral = node => node.type === 'ArrayExpression';
const isArrayLiteralHasTrailingComma = (node, sourceCode) => {
if (node.elements.length === 0) {
return false;
}
return isCommaToken(sourceCode.getLastToken(node, 1));
};
const getParenthesizedRange = (node, sourceCode) => {
const [firstToken = node, lastToken = node] = getParentheses(node, sourceCode);
const [start] = firstToken.range;
const [, end] = lastToken.range;
return [start, end];
};
function fixConcat(node, sourceCode, fixableArguments) {
const array = node.callee.object;
const concatCallArguments = node.arguments;
const arrayParenthesizedRange = getParenthesizedRange(array, sourceCode);
const arrayIsArrayLiteral = isArrayLiteral(array);
const arrayHasTrailingComma = arrayIsArrayLiteral && isArrayLiteralHasTrailingComma(array, sourceCode);
const getRangeAfterArray = () => {
const [, start] = arrayParenthesizedRange;
const [, end] = node.range;
return [start, end];
};
const getArrayLiteralElementsText = (node, keepTrailingComma) => {
if (
!keepTrailingComma &&
isArrayLiteralHasTrailingComma(node, sourceCode)
) {
const start = node.range[0] + 1;
const end = sourceCode.getLastToken(node, 1).range[0];
return sourceCode.text.slice(start, end);
}
return sourceCode.getText(node, -1, -1);
};
const getFixedText = () => {
const nonEmptyArguments = fixableArguments
.filter(({node, isArrayLiteral}) => (!isArrayLiteral || node.elements.length > 0));
const lastArgument = nonEmptyArguments[nonEmptyArguments.length - 1];
let text = nonEmptyArguments
.map(({node, isArrayLiteral, isSpreadable}) => {
if (isArrayLiteral) {
return getArrayLiteralElementsText(node, node === lastArgument.node);
}
const [start, end] = getParenthesizedRange(node, sourceCode);
let text = sourceCode.text.slice(start, end);
if (isSpreadable) {
if (
!isParenthesized(node, sourceCode) &&
shouldAddParenthesesToSpreadElementArgument(node)
) {
text = `(${text})`;
}
text = `...${text}`;
}
return text || ' ';
})
.join(', ');
if (!text) {
return '';
}
if (arrayIsArrayLiteral) {
if (array.elements.length > 0) {
text = ` ${text}`;
if (!arrayHasTrailingComma) {
text = `,${text}`;
}
if (
arrayHasTrailingComma &&
(!lastArgument.isArrayLiteral || !isArrayLiteralHasTrailingComma(lastArgument.node, sourceCode))
) {
text = `${text},`;
}
}
} else {
text = `, ${text}`;
}
return text;
};
function removeArguments(fixer) {
const [firstArgument] = concatCallArguments;
const lastArgument = concatCallArguments[fixableArguments.length - 1];
const [start] = getParenthesizedRange(firstArgument, sourceCode);
let [, end] = sourceCode.getTokenAfter(lastArgument, isCommaToken).range;
const textAfter = sourceCode.text.slice(end);
const [leadingSpaces] = textAfter.match(/^\s*/);
end += leadingSpaces.length;
return fixer.replaceTextRange([start, end], '');
}
return function * (fixer) {
// Fixed code always starts with `[`
if (
!arrayIsArrayLiteral &&
needsSemicolon(sourceCode.getTokenBefore(node), sourceCode, '[')
) {
yield fixer.insertTextBefore(node, ';');
}
yield (
concatCallArguments.length - fixableArguments.length === 0 ?
fixer.replaceTextRange(getRangeAfterArray(), '') :
removeArguments(fixer)
);
const text = getFixedText();
if (arrayIsArrayLiteral) {
const closingBracketToken = sourceCode.getLastToken(array);
yield fixer.insertTextBefore(closingBracketToken, text);
} else {
// The array is already accessing `.concat`, there should not any case need add extra `()`
yield fixer.insertTextBeforeRange(arrayParenthesizedRange, '[...');
yield fixer.insertTextAfterRange(arrayParenthesizedRange, text);
yield fixer.insertTextAfterRange(arrayParenthesizedRange, ']');
}
};
}
const getConcatArgumentSpreadable = (node, scope) => {
if (node.type === 'SpreadElement') {
return;
}
if (isArrayLiteral(node)) {
return {node, isArrayLiteral: true};
}
const result = getStaticValue(node, scope);
if (!result) {
return;
}
const isSpreadable = Array.isArray(result.value);
return {node, isSpreadable};
};
function getConcatFixableArguments(argumentsList, scope) {
const fixableArguments = [];
for (const node of argumentsList) {
const result = getConcatArgumentSpreadable(node, scope);
if (result) {
fixableArguments.push(result);
} else {
break;
}
}
return fixableArguments;
}
const create = context => {

@@ -28,6 +226,6 @@ const sourceCode = context.getSourceCode();

return {
[selector](node) {
[arrayFromCallSelector](node) {
context.report({
node,
messageId: MESSAGE_ID,
messageId: ERROR_ARRAY_FROM,
fix: fixer => {

@@ -47,2 +245,57 @@ const [arrayLikeArgument, mapFn, thisArgument] = node.arguments.map(node => getSource(node));

});
},
[arrayConcatCallSelector](node) {
const scope = context.getScope();
const staticResult = getStaticValue(node.callee.object, scope);
if (staticResult && !Array.isArray(staticResult.value)) {
return;
}
const problem = {
node: node.callee.property,
messageId: ERROR_ARRAY_CONCAT
};
const fixableArguments = getConcatFixableArguments(node.arguments, scope);
if (fixableArguments.length > 0 || node.arguments.length === 0) {
problem.fix = fixConcat(node, sourceCode, fixableArguments);
context.report(problem);
return;
}
const [firstArgument, ...restArguments] = node.arguments;
if (firstArgument.type === 'SpreadElement') {
context.report(problem);
return;
}
const fixableArgumentsAfterFirstArgument = getConcatFixableArguments(restArguments, scope);
problem.suggest = [
{
messageId: SUGGESTION_CONCAT_ARGUMENT_IS_SPREADABLE,
isSpreadable: true
},
{
messageId: SUGGESTION_CONCAT_ARGUMENT_IS_NOT_SPREADABLE,
isSpreadable: false
}
].map(({messageId, isSpreadable}) => ({
messageId,
fix: fixConcat(
node,
sourceCode,
// When apply suggestion, we also merge fixable arguments after the first one
[
{
node: firstArgument,
isSpreadable
},
...fixableArgumentsAfterFirstArgument
]
)
}));
context.report(problem);
}

@@ -49,0 +302,0 @@ };

@@ -59,2 +59,3 @@ 'use strict';

const create = context => {
const onlySingleLine = context.options[0] === 'only-single-line';
const sourceCode = context.getSourceCode();

@@ -80,2 +81,7 @@ const scopeToNamesGeneratedByFixer = new WeakMap();

const isSingleLineNode = node => {
const [start, end] = node.range.map(index => sourceCode.getLocFromIndex(index));
return start.line === end.line;
};
function merge(options, mergeOptions) {

@@ -194,2 +200,9 @@ const {

if (
onlySingleLine &&
[consequent, alternate, node.test].some(node => !isSingleLineNode(node))
) {
return;
}
const result = merge({node, consequent, alternate}, {

@@ -205,3 +218,2 @@ checkThrowStatement: true,

const scope = context.getScope();
const sourceCode = context.getSourceCode();

@@ -259,2 +271,9 @@ context.report({

const schema = [
{
enum: ['always', 'only-single-line'],
default: 'always'
}
];
module.exports = {

@@ -270,4 +289,5 @@ create,

},
schema,
fixable: 'code'
}
};
'use strict';
const path = require('path');
const astUtils = require('eslint-ast-utils');
const {defaultsDeep, upperFirst, lowerFirst} = require('lodash');

@@ -392,4 +391,6 @@

message.push(`Please rename the ${nameTypeText} \`${discouragedName}\`.`);
message.push(`Suggested names are: ${replacementsText}.`);
message.push(
`Please rename the ${nameTypeText} \`${discouragedName}\`.`,
`Suggested names are: ${replacementsText}.`
);
}

@@ -434,2 +435,12 @@

const isStaticRequire = node => Boolean(
node &&
node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'require' &&
node.arguments.length === 1 &&
node.arguments[0].type === 'Literal' &&
typeof node.arguments[0].value === 'string'
);
const isDefaultOrNamespaceImportName = identifier => {

@@ -462,3 +473,3 @@ if (

identifier.parent.id === identifier &&
astUtils.isStaticRequire(identifier.parent.init)
isStaticRequire(identifier.parent.init)
) {

@@ -573,3 +584,3 @@ return true;

identifiers: variable.identifiers,
references: variable.references.concat(outerClassVariable.references)
references: [...variable.references, ...outerClassVariable.references]
};

@@ -645,3 +656,6 @@

const scopes = variable.references.map(reference => reference.from).concat(variable.scope);
const scopes = [
...variable.references.map(reference => reference.from),
variable.scope
];
variableReplacements.samples = variableReplacements.samples.map(

@@ -679,7 +693,11 @@ name => avoidCapture(name, scopes, ecmaVersion, isSafeName)

const checkVariables = scope => {
scope.variables.forEach(variable => checkPossiblyWeirdClassVariable(variable));
for (const variable of scope.variables) {
checkPossiblyWeirdClassVariable(variable);
}
};
const checkChildScopes = scope => {
scope.childScopes.forEach(scope => checkScope(scope));
for (const childScope of scope.childScopes) {
checkScope(childScope);
}
};

@@ -686,0 +704,0 @@

'use strict';
const {uniq} = require('lodash');
const {uniq, flatten} = require('lodash');
const getReferences = scope => uniq(
scope.references.concat(
...scope.childScopes.map(scope => getReferences(scope))
)
);
const getReferences = scope => uniq([
...scope.references,
...flatten(scope.childScopes.map(scope => getReferences(scope)))
]);
module.exports = getReferences;
'use strict';
const isSameNode = require('./is-same-node');
const hasSameRange = require('./has-same-range');

@@ -9,4 +9,9 @@ module.exports = identifier =>

identifier.parent.parent.type === 'Property' &&
isSameNode(identifier, identifier.parent.parent.key) &&
(
identifier === identifier.parent.parent.key ||
// In `babel-eslint` parent.key is not reference of identifier, #444
// issue https://github.com/babel/babel-eslint/issues/809
hasSameRange(identifier, identifier.parent.parent.key)
) &&
identifier.parent.parent.value === identifier.parent &&
identifier.parent.parent.shorthand;
'use strict';
module.exports = (node, value) => node && node.type === 'Literal' && node.value === value;
module.exports = (node, value) => {
if (!node || node.type !== 'Literal') {
return false;
}
if (value === null) {
return node.raw === 'null';
}
return node.value === value;
};
'use strict';
const isSameNode = require('./is-same-node');
/**

@@ -13,3 +11,3 @@ * Finds the eslint-scope reference in the given scope.

const references = scope.references
.filter(reference => isSameNode(reference.identifier, node));
.filter(reference => reference.identifier === node);

@@ -16,0 +14,0 @@ if (references.length === 1) {

'use strict';
const isSameNode = require('./is-same-node');
const hasSameRange = require('./has-same-range');

@@ -8,2 +8,7 @@ module.exports = identifier =>

identifier.parent.shorthand &&
isSameNode(identifier, identifier.parent.key);
(
identifier === identifier.parent.key ||
// In `babel-eslint` parent.key is not reference of identifier, #444
// issue https://github.com/babel/babel-eslint/issues/809
hasSameRange(identifier, identifier.parent.key)
);

@@ -11,3 +11,4 @@ 'use strict';

max,
property = ''
property = '',
includeOptional = false
} = {

@@ -24,6 +25,9 @@ min: 0,

`[${prefix}callee.type="MemberExpression"]`,
`[${prefix}callee.computed=false]`,
`[${prefix}callee.property.type="Identifier"]`
];
if (!includeOptional) {
selector.push(`[${prefix}callee.computed=false]`);
}
if (name) {

@@ -42,4 +46,6 @@ selector.push(`[${prefix}callee.property.name="${name}"]`);

if (object) {
selector.push(`[${prefix}callee.object.type="Identifier"]`);
selector.push(`[${prefix}callee.object.name="${object}"]`);
selector.push(
`[${prefix}callee.object.type="Identifier"]`,
`[${prefix}callee.object.name="${object}"]`
);
}

@@ -46,0 +52,0 @@

'use strict';
const {isOpeningParenToken, isClosingParenToken} = require('eslint-utils');
const isNewExpressionWithParentheses = require('./is-new-expression-with-parentheses');

@@ -14,23 +14,2 @@ // Determine whether this node is a decimal integer literal.

/**
Determine if a constructor function is newed-up with parens.
@param {Node} node - The `NewExpression` node to be checked.
@param {SourceCode} sourceCode - The source code object.
@returns {boolean} True if the constructor is called with parens.
Copied from https://github.com/eslint/eslint/blob/cc4871369645c3409dc56ded7a555af8a9f63d51/lib/rules/no-extra-parens.js#L252
*/
function isNewExpressionWithParentheses(node, sourceCode) {
if (node.arguments.length > 0) {
return true;
}
const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2);
// The expression should end with its own parens, for example, `new new Foo()` is not a new expression with parens.
return isOpeningParenToken(penultimateToken) &&
isClosingParenToken(lastToken) &&
node.callee.range[1] < node.range[1];
}
/**
Check if parentheses should to be added to a `node` when it's used as an `object` of `MemberExpression`.

@@ -37,0 +16,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc