Socket
Socket
Sign inDemoInstall

eslint-plugin-unicorn

Package Overview
Dependencies
Maintainers
1
Versions
106
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 8.0.2 to 9.0.0

rules/prefer-event-key.js

2

index.js

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

'unicorn/prefer-add-event-listener': 'error',
'unicorn/prefer-event-key': 'error',
'unicorn/prefer-exponentiation-operator': 'error',
'unicorn/prefer-flat-map': 'error',
'unicorn/prefer-includes': 'error',

@@ -45,0 +47,0 @@ 'unicorn/prefer-node-append': 'error',

29

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

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

"engines": {
"node": ">=6"
"node": ">=8"
},

@@ -48,14 +48,15 @@ "scripts": {

"devDependencies": {
"ava": "^1.1.0",
"ava": "^1.4.1",
"babel-eslint": "^10.0.0",
"chalk": "^2.4.2",
"coveralls": "^3.0.0",
"del": "^3.0.0",
"del": "^4.1.1",
"eslint": "^5.12.0",
"eslint-ava-rule-tester": "^3.0.0",
"eslint-plugin-eslint-plugin": "2.1.0",
"execa": "^1.0.0",
"listr": "^0.14.1",
"nyc": "^13.1.0",
"nyc": "^14.1.1",
"pify": "^4.0.1",
"tempy": "^0.2.1",
"tempy": "^0.3.0",
"xo": "^0.24.0"

@@ -70,3 +71,19 @@ },

]
},
"xo": {
"plugins": [
"eslint-plugin"
],
"extends": [
"plugin:eslint-plugin/all"
],
"overrides": [
{
"files": "rules/utils/*.js",
"rules": {
"eslint-plugin/require-meta-docs-url": "off"
}
}
]
}
}

@@ -60,3 +60,5 @@ # eslint-plugin-unicorn [![Build Status](https://travis-ci.org/sindresorhus/eslint-plugin-unicorn.svg?branch=master)](https://travis-ci.org/sindresorhus/eslint-plugin-unicorn) [![Coverage Status](https://coveralls.io/repos/github/sindresorhus/eslint-plugin-unicorn/badge.svg?branch=master)](https://coveralls.io/github/sindresorhus/eslint-plugin-unicorn?branch=master)

"unicorn/prefer-add-event-listener": "error",
"unicorn/prefer-event-key": "error",
"unicorn/prefer-exponentiation-operator": "error",
"unicorn/prefer-flat-map": "error",
"unicorn/prefer-includes": "error",

@@ -92,5 +94,5 @@ "unicorn/prefer-node-append": "error",

- [no-console-spaces](docs/rules/no-console-spaces.md) - Do not use leading/trailing space between `console.log` parameters. *(fixable)*
- [no-fn-reference-in-iterator](docs/rules/no-fn-reference-in-iterator.md) - Prevents passing a function reference directly to iterator methods. *(fixable)*
- [no-for-loop](docs/rules/no-for-loop.md) - Do not use a `for` loop that can be replaced with a `for-of` loop. *(fixable)*
- [no-hex-escape](docs/rules/no-hex-escape.md) - Enforce the use of unicode escapes instead of hexadecimal escapes. *(fixable)*
- [no-fn-reference-in-iterator](docs/rules/no-fn-reference-in-iterator.md) - Prevent passing a function reference directly to iterator methods. *(fixable)*
- [no-for-loop](docs/rules/no-for-loop.md) - Do not use a `for` loop that can be replaced with a `for-of` loop. *(partly fixable)*
- [no-hex-escape](docs/rules/no-hex-escape.md) - Enforce the use of Unicode escapes instead of hexadecimal escapes. *(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)*

@@ -103,13 +105,15 @@ - [no-process-exit](docs/rules/no-process-exit.md) - Disallow `process.exit()`.

- [number-literal-case](docs/rules/number-literal-case.md) - Enforce lowercase identifier and uppercase value for number literals. *(fixable)*
- [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) - Prefer `addEventListener` over `on`-functions. *(fixable)*
- [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) - Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. *(partly fixable)*
- [prefer-event-key](docs/rules/prefer-event-key.md) - Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. *(partly fixable)*
- [prefer-exponentiation-operator](docs/rules/prefer-exponentiation-operator.md) - Prefer the exponentiation operator over `Math.pow()` *(fixable)*
- [prefer-flat-map](docs/rules/prefer-flat-map.md) - Prefer `.flatMap(…)` over `.map(…).flat()`. *(fixable)*
- [prefer-includes](docs/rules/prefer-includes.md) - Prefer `.includes()` over `.indexOf()` when checking for existence or non-existence. *(fixable)*
- [prefer-node-append](docs/rules/prefer-node-append.md) - Prefer `append` over `appendChild`. *(fixable)*
- [prefer-node-remove](docs/rules/prefer-node-remove.md) - Prefer `remove` over `parentNode.removeChild` and `parentElement.removeChild`. *(fixable)*
- [prefer-query-selector](docs/rules/prefer-query-selector.md) - Prefer `querySelector` over `getElementById`, `querySelectorAll` over `getElementsByClassName` and `getElementsByTagName`. *(partly fixable)*
- [prefer-node-append](docs/rules/prefer-node-append.md) - Prefer `Node#append()` over `Node#appendChild()`. *(fixable)*
- [prefer-node-remove](docs/rules/prefer-node-remove.md) - Prefer `node.remove()` over `parentNode.removeChild(node)` and `parentElement.removeChild(node)`. *(fixable)*
- [prefer-query-selector](docs/rules/prefer-query-selector.md) - Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. *(partly fixable)*
- [prefer-spread](docs/rules/prefer-spread.md) - Prefer the spread operator over `Array.from()`. *(fixable)*
- [prefer-starts-ends-with](docs/rules/prefer-starts-ends-with.md) - Prefer `String#startsWith` & `String#endsWith` over more complex alternatives.
- [prefer-text-content](docs/rules/prefer-text-content.md) - Prefer `textContent` over `innerText`. *(fixable)*
- [prefer-starts-ends-with](docs/rules/prefer-starts-ends-with.md) - Prefer `String#startsWith()` & `String#endsWith()` over more complex alternatives.
- [prefer-text-content](docs/rules/prefer-text-content.md) - Prefer `.textContent` over `.innerText`. *(fixable)*
- [prefer-type-error](docs/rules/prefer-type-error.md) - Enforce throwing `TypeError` in type checking conditions. *(fixable)*
- [prevent-abbreviations](docs/rules/prevent-abbreviations.md) - Prevent abbreviations *(partly fixable)*
- [prevent-abbreviations](docs/rules/prevent-abbreviations.md) - Prevent abbreviations. *(partly fixable)*
- [regex-shorthand](docs/rules/regex-shorthand.md) - Enforce the use of regex shorthands to improve readability. *(fixable)*

@@ -142,9 +146,12 @@ - [throw-new-error](docs/rules/throw-new-error.md) - Require `new` when throwing an error. *(fixable)*

- [Sindre Sorhus](https://github.com/sindresorhus)
- [Jeroen Engels](https://github.com/jfmengels)
- [Sam Verschueren](https://github.com/SamVerschueren)
- [futpib](https://github.com/futpib)
###### Former
- [Jeroen Engels](https://github.com/jfmengels)
## License
MIT
'use strict';
const astUtils = require('eslint-ast-utils');
const avoidCapture = require('./utils/avoid-capture');
const getDocsUrl = require('./utils/get-docs-url');

@@ -28,19 +29,12 @@

// TODO: Use `./utils/avoid-capture.js` instead
function indexifyName(name, scope) {
const variables = scope.variableScope.set;
const create = context => {
const {
ecmaVersion
} = context.parserOptions;
let index = 1;
while (variables.has(index === 1 ? name : name + index)) {
index++;
}
return name + (index === 1 ? '' : index);
}
const create = context => {
const options = Object.assign({}, {
const options = {
name: 'error',
caughtErrorsIgnorePattern: '^_$'
}, context.options[0]);
caughtErrorsIgnorePattern: '^_$',
...context.options[0]
};

@@ -99,4 +93,5 @@ const {scopeManager} = context.getSourceCode();

const errName = indexifyName(name, context.getScope());
push(params.length === 0 || params[0].name === errName || errName);
const scope = context.getScope();
const errorName = avoidCapture(name, [scope.variableScope], ecmaVersion);
push(params.length === 0 || params[0].name === errorName || errorName);
}

@@ -122,3 +117,4 @@ },

const errName = indexifyName(name, context.getScope());
const scope = context.getScope();
const errName = avoidCapture(name, [scope.variableScope], ecmaVersion);
push(node.param.name === errName || errName);

@@ -125,0 +121,0 @@ },

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

node: expressionNode.parent,
message: 'Pass a message to the error constructor'
message: 'Pass a message to the error constructor.'
});

@@ -62,3 +62,3 @@ }

node: expressionNode.parent,
message: 'Error message should not be an empty string'
message: 'Error message should not be an empty string.'
});

@@ -65,0 +65,0 @@ }

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

const pascalCase = str => upperfirst(camelCase(str));
const pascalCase = string => upperfirst(camelCase(string));
const numberRegex = /(\d+)/;

@@ -16,13 +16,13 @@ const PLACEHOLDER = '\uFFFF\uFFFF\uFFFF';

function ignoreNumbers(fn) {
return str => {
return string => {
const stack = [];
let execResult = numberRegex.exec(str);
let execResult = numberRegex.exec(string);
while (execResult) {
stack.push(execResult[0]);
str = str.replace(execResult[0], PLACEHOLDER);
execResult = numberRegex.exec(str);
string = string.replace(execResult[0], PLACEHOLDER);
execResult = numberRegex.exec(string);
}
let withCase = fn(str);
let withCase = fn(string);

@@ -56,6 +56,29 @@ while (stack.length > 0) {

/**
Get the cases specified by the option.
@param {unknown} context
@returns {string[]} The chosen cases.
*/
function getChosenCases(context) {
const option = context.options[0] || {};
if (option.case) {
return [option.case];
}
if (option.cases) {
const cases = Object.keys(option.cases)
.filter(cases => option.cases[cases]);
return cases.length > 0 ? cases : ['kebabCase'];
}
return ['kebabCase'];
}
function fixFilename(chosenCase, filename) {
return filename
.split('.')
.map(ignoreNumbers(chosenCase.fn))
.map(ignoreNumbers(cases[chosenCase].fn))
.join('.');

@@ -73,9 +96,27 @@ }

/**
Turns `[a, b, c]` into `a, b, or c`.
@param {string[]} words
@returns {string}
*/
function englishishJoinWords(words) {
if (words.length === 1) {
return words[0];
}
if (words.length === 2) {
return `${words[0]} or ${words[1]}`;
}
words = words.slice();
const last = words.pop();
return `${words.join(', ')}, or ${last}`;
}
const create = context => {
const options = context.options[0] || {};
const chosenCases = getChosenCases(context);
const filenameWithExtension = context.getFilename();
const chosenCase = cases[options.case || 'kebabCase'];
const filenameWithExt = context.getFilename();
if (filenameWithExt === '<text>') {
if (filenameWithExtension === '<text>') {
return {};

@@ -86,4 +127,4 @@ }

Program: node => {
const extension = path.extname(filenameWithExt);
const filename = path.basename(filenameWithExt, extension);
const extension = path.extname(filenameWithExtension);
const filename = path.basename(filenameWithExtension, extension);

@@ -95,9 +136,13 @@ if (filename + extension === 'index.js') {

const splitName = splitFilename(filename);
const fixedFilename = fixFilename(chosenCase, splitName.trailing);
const renameFilename = splitName.leading + fixedFilename + extension;
const fixedFilenames = chosenCases.map(case_ => fixFilename(case_, splitName.trailing));
const renamedFilenames = fixedFilenames.map(x => splitName.leading + x + extension);
if (fixedFilename !== splitName.trailing) {
if (!fixedFilenames.includes(splitName.trailing)) {
context.report({
node,
message: `Filename is not in ${chosenCase.name}. Rename it to \`${renameFilename}\`.`
messageId: chosenCases.length > 1 ? 'renameToCases' : 'renameToCase',
data: {
chosenCases: englishishJoinWords(chosenCases.map(x => cases[x].name)),
renamedFilenames: englishishJoinWords(renamedFilenames.map(x => `\`${x}\``))
}
});

@@ -110,13 +155,39 @@ }

const schema = [{
type: 'object',
properties: {
case: {
enum: [
'camelCase',
'snakeCase',
'kebabCase',
'pascalCase'
]
oneOf: [
{
properties: {
case: {
enum: [
'camelCase',
'snakeCase',
'kebabCase',
'pascalCase'
]
}
},
additionalProperties: false
},
{
properties: {
cases: {
properties: {
camelCase: {
type: 'boolean'
},
snakeCase: {
type: 'boolean'
},
kebabCase: {
type: 'boolean'
},
pascalCase: {
type: 'boolean'
}
},
additionalProperties: false
}
},
additionalProperties: false
}
}
]
}];

@@ -131,4 +202,8 @@

},
schema
schema,
messages: {
renameToCase: 'Filename is not in {{chosenCases}}. Rename it to {{renamedFilenames}}.',
renameToCases: 'Filename is not in {{chosenCases}}. Rename it to {{renamedFilenames}}.'
}
}
};
'use strict';
const getDocsUrl = require('./utils/get-docs-url');
const regexp = /^(@.*?\/.*?|[./]+?.*?)(?:\/(?:index(?:\.js)?)?)$/;
const isImportingIndex = m => regexp.test(m);
const normalize = m => m.replace(regexp, '$1');
const regexp = /^(@.*?\/.*?|[./]+?.*?)(?:\/(\.|(?:index(?:\.js)?))?)$/;
const isImportingIndex = value => regexp.test(value);
const normalize = value => value.replace(regexp, '$1');
const importIndex = (context, node, m) => {
if (isImportingIndex(m.value)) {
const importIndex = (context, node, argument) => {
if (isImportingIndex(argument.value)) {
context.report({
node,
message: 'Do not reference the index file directly',
fix: fixer => fixer.replaceText(m, `'${normalize(m.value)}'`)
message: 'Do not reference the index file directly.',
fix: fixer => fixer.replaceText(argument, `'${normalize(argument.value)}'`)
});

@@ -15,0 +15,0 @@ }

@@ -36,6 +36,6 @@ 'use strict';

const numberOfArgs = getNumberOfArguments(node);
const arg = node.arguments[0];
const argString = numberOfArgs === 1 ? 'x' : 'a, b';
const argument = node.arguments[0];
const argumentString = numberOfArgs === 1 ? 'x' : 'a, b';
return fixer => fixer.replaceText(arg, `${numberOfArgs === 1 ? argString : `(${argString})`} => ${parseArgument(context, arg)}(${argString})`);
return fixer => fixer.replaceText(argument, `${numberOfArgs === 1 ? argumentString : `(${argumentString})`} => ${parseArgument(context, argument)}(${argumentString})`);
};

@@ -42,0 +42,0 @@

'use strict';
const getDocsUrl = require('./utils/get-docs-url');
const defaultElementName = 'element';
const isLiteralValue = value => node => node && node.type === 'Literal' && node.value === value;

@@ -88,50 +89,2 @@ const isLiteralZero = isLiteralValue(0);

const isMatchingMemberExpression = (memberExpression, objectIdentifierName, propertyIdentifierName) => {
if (!memberExpression || memberExpression.type !== 'MemberExpression') {
return false;
}
const {object, property} = memberExpression;
return isIdentifierWithName(object, objectIdentifierName) &&
isIdentifierWithName(property, propertyIdentifierName);
};
const getElementIdentifierInfo = (forStatement, arrayIdentifierName, indexIdentifierName) => {
const {body} = forStatement;
if (!body ||
body.type !== 'BlockStatement'
) {
return;
}
const [elementVariableDeclaration] = body.body;
if (!elementVariableDeclaration ||
elementVariableDeclaration.type !== 'VariableDeclaration'
) {
return;
}
if (elementVariableDeclaration.declarations.length !== 1) {
return;
}
const [elementVariableDeclarator] = elementVariableDeclaration.declarations;
if (elementVariableDeclarator.id.type !== 'Identifier') {
return;
}
if (!isMatchingMemberExpression(elementVariableDeclarator.init, arrayIdentifierName, indexIdentifierName)) {
return;
}
return {
elementVariableDeclaration,
elementIdentifierName: elementVariableDeclarator.id.name
};
};
const isLiteralOnePlusIdentifierWithName = (node, identifierName) => {

@@ -170,16 +123,50 @@ if (node && node.type === 'BinaryExpression' && node.operator === '+') {

const isOnlyArrayOfIndexVariableRead = (arrayReferences, indexIdentifierName) => {
return arrayReferences.every(reference => {
const node = reference.identifier.parent;
if (node.type !== 'MemberExpression') {
return false;
}
if (node.property.name !== indexIdentifierName) {
return false;
}
if (node.parent.type === 'AssignmentExpression' && node.parent.left === node) {
return false;
}
return true;
});
};
const getRemovalRange = (node, sourceCode) => {
const nodeText = sourceCode.getText(node);
const {line} = sourceCode.getLocFromIndex(node.range[0]);
const lineText = sourceCode.lines[line - 1];
const declarationNode = node.parent;
const isOnlyNodeOnItsLine = lineText.trim() === nodeText;
if (isOnlyNodeOnItsLine) {
return [
if (declarationNode.declarations.length === 1) {
const {line} = sourceCode.getLocFromIndex(declarationNode.range[0]);
const lineText = sourceCode.lines[line - 1];
const isOnlyNodeOnLine = lineText.trim() === sourceCode.getText(declarationNode);
return isOnlyNodeOnLine ? [
sourceCode.getIndexFromLoc({line, column: 0}),
sourceCode.getIndexFromLoc({line: line + 1, column: 0})
] : declarationNode.range;
}
const index = declarationNode.declarations.indexOf(node);
if (index === 0) {
return [
node.range[0],
declarationNode.declarations[1].range[0]
];
}
return node.range;
return [
declarationNode.declarations[index - 1].range[1],
node.range[1]
];
};

@@ -225,8 +212,20 @@

const isIndexVariableUsedElsewhereInTheLoopBody = (indexVariable, bodyScope) => {
const isIndexVariableUsedElsewhereInTheLoopBody = (indexVariable, bodyScope, arrayIdentifierName) => {
const inBodyReferences = indexVariable.references.filter(reference => scopeContains(bodyScope, reference.from));
// One reference in the body would be the one in the element variable declaration like `const el = arr[i]`.
// Any reference besides that should retain the index variable.
return inBodyReferences.length > 1;
const referencesOtherThanArrayAccess = inBodyReferences.filter(reference => {
const node = reference.identifier.parent;
if (node.type !== 'MemberExpression') {
return true;
}
if (node.object.name !== arrayIdentifierName) {
return true;
}
return false;
});
return referencesOtherThanArrayAccess.length > 0;
};

@@ -249,2 +248,12 @@

const getReferencesInChildScopes = (scope, name) => {
const references = scope.references.filter(reference => reference.identifier.name === name);
return [
...references,
...scope.childScopes
.map(s => getReferencesInChildScopes(s, name))
.reduce((acc, scopeReferences) => [...acc, ...scopeReferences], [])
];
};
const create = context => {

@@ -272,10 +281,25 @@ const sourceCode = context.getSourceCode();

const elementIdentifierInfo = getElementIdentifierInfo(node, arrayIdentifierName, indexIdentifierName);
if (!node.body || node.body.type !== 'BlockStatement') {
return;
}
if (!elementIdentifierInfo) {
const forScope = scopeManager.acquire(node);
const bodyScope = scopeManager.acquire(node.body);
const indexVariable = resolveIdentifierName(indexIdentifierName, bodyScope);
if (isIndexVariableAssignedToInTheLoopBody(indexVariable, bodyScope)) {
return;
}
const {elementIdentifierName, elementVariableDeclaration} = elementIdentifierInfo;
const arrayReferences = getReferencesInChildScopes(bodyScope, arrayIdentifierName);
if (arrayReferences.length === 0) {
return;
}
if (!isOnlyArrayOfIndexVariableRead(arrayReferences, indexIdentifierName)) {
return;
}
const problem = {

@@ -286,17 +310,23 @@ node,

const forScope = scopeManager.acquire(node);
const bodyScope = scopeManager.acquire(node.body);
const elementReference = arrayReferences.find(reference => {
const node = reference.identifier.parent;
const indexVariable = resolveIdentifierName(indexIdentifierName, bodyScope);
const elementVariable = resolveIdentifierName(elementIdentifierName, bodyScope);
if (node.parent.type !== 'VariableDeclarator') {
return false;
}
const shouldFix = !someVariablesLeakOutOfTheLoop(node, [indexVariable, elementVariable], forScope) &&
!isIndexVariableAssignedToInTheLoopBody(indexVariable, bodyScope);
return true;
});
const elementNode = elementReference && elementReference.identifier.parent.parent;
const elementIdentifierName = elementNode && elementNode.id.name;
const elementVariable = elementIdentifierName && resolveIdentifierName(elementIdentifierName, bodyScope);
const shouldFix = !someVariablesLeakOutOfTheLoop(node, [indexVariable, elementVariable].filter(Boolean), forScope);
if (shouldFix) {
problem.fix = fixer => {
const shouldGenerateIndex = isIndexVariableUsedElsewhereInTheLoopBody(indexVariable, bodyScope);
const shouldGenerateIndex = isIndexVariableUsedElsewhereInTheLoopBody(indexVariable, bodyScope, arrayIdentifierName);
const index = indexIdentifierName;
const element = elementIdentifierName;
const element = elementIdentifierName || defaultElementName;
const array = arrayIdentifierName;

@@ -313,5 +343,11 @@

], replacement),
...arrayReferences.map(reference => {
if (reference === elementReference) {
return undefined;
}
fixer.removeRange(getRemovalRange(elementVariableDeclaration, sourceCode))
];
return fixer.replaceText(reference.identifier.parent, element);
}),
elementNode && fixer.removeRange(getRemovalRange(elementNode, sourceCode))
].filter(Boolean);
};

@@ -318,0 +354,0 @@ }

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

node,
message: 'Use unicode escapes instead of hexadecimal escapes.',
message: 'Use Unicode escapes instead of hexadecimal escapes.',
fix: fixer => fixer.replaceTextRange([node.start, node.end], fixedValue)

@@ -13,0 +13,0 @@ });

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

let processEventHandler = null;
let processEventHandler;

@@ -34,3 +34,3 @@ return {

if (node === processEventHandler) {
processEventHandler = null;
processEventHandler = undefined;
}

@@ -37,0 +37,0 @@ }

@@ -31,5 +31,4 @@ 'use strict';

let pattern = null;
let flags = null;
let pattern;
let flags;
if (hasRegExp) {

@@ -36,0 +35,0 @@ ({pattern} = args[0].regex);

@@ -10,5 +10,5 @@ 'use strict';

const indicator = value[1].toLowerCase();
const val = value.slice(2).toUpperCase();
const newValue = value.slice(2).toUpperCase();
return `0${indicator}${val}`;
return `0${indicator}${newValue}`;
};

@@ -15,0 +15,0 @@

@@ -15,14 +15,31 @@ 'use strict';

const parseArgument = (context, arg) => {
if (arg.type === 'Identifier') {
return arg.name;
const parseArgument = (source, arg) => {
const text = source.getText(arg);
switch (arg.type) {
case 'Identifier':
return arg.name;
case 'Literal':
return text;
case 'CallExpression':
return text;
case 'UnaryExpression':
return text;
default:
// Handle cases like Math.pow(2, 2-1);
return `(${text})`;
}
return context.getSourceCode().getText(arg);
};
const fix = (context, node, fixer) => {
const base = parseArgument(context, node.arguments[0]);
const exponent = parseArgument(context, node.arguments[1]);
const source = context.getSourceCode();
const comments = source.getCommentsInside(node);
if (comments && comments.length > 0) {
return;
}
const base = parseArgument(source, node.arguments[0]);
const exponent = parseArgument(source, node.arguments[1]);
const replacement = `${base} ** ${exponent}`;

@@ -29,0 +46,0 @@

'use strict';
const getDocsUrl = require('./utils/get-docs-url');
const isMethodNamed = require('./utils/is-method-named');
const isIndexOf = node => {
return (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'indexOf'
);
};
const isNegativeOne = (operator, value) => operator === '-' && value === 1;
const getSourceCode = (context, node) => (
context.getSourceCode().getText(node)
);
const report = (context, node, target, pattern) => {
const sourceCode = context.getSourceCode();
const memberExpressionNode = target.parent;
const dotToken = sourceCode.getTokenBefore(memberExpressionNode.property);
const targetSource = sourceCode.getText().slice(memberExpressionNode.range[0], dotToken.range[0]);
const patternSource = sourceCode.getText(pattern);
const report = (context, node, target, pattern) => {
const targetSource = getSourceCode(context, target);
const patternSource = getSourceCode(context, pattern);
context.report({

@@ -37,3 +29,3 @@ node,

if (isIndexOf(left)) {
if (isMethodNamed(left, 'indexOf')) {
const target = left.callee.object;

@@ -40,0 +32,0 @@ const pattern = left.arguments[0];

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

node,
message: 'Prefer `append` over `appendChild`',
message: 'Prefer `Node#append()` over `Node#appendChild()`.',
fix: fixer => fixer.replaceText(callee.property, 'append')

@@ -17,0 +17,0 @@ });

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

node,
message: `Prefer \`remove\` over \`${callerName}.removeChild\``,
message: `Prefer \`${argumentName}.remove()\` over \`${callerName}.removeChild(${argumentName})\`.`,
fix: fixer => fixer.replaceText(node, `${argumentName}.remove()`)

@@ -73,0 +73,0 @@ });

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

const getReplacementForClass = value => value.match(/\S+/g).map(e => `.${e}`).join('');
const getQuotedReplacement = (node, value) => {

@@ -98,3 +99,3 @@ const leftQuote = node.raw.charAt(0);

node,
message: `Prefer \`${preferedSelector}\` over \`${identifierName}\`.`
message: `Prefer \`.${preferedSelector}()\` over \`.${identifierName}()\`.`
};

@@ -101,0 +102,0 @@

@@ -15,10 +15,10 @@ 'use strict';

const isArrayLike = arg => arg && arg.type !== 'ObjectExpression';
const isArrayLike = argument => argument && argument.type !== 'ObjectExpression';
const parseArgument = (context, arg) => {
if (arg.type === 'Identifier') {
return arg.name;
const parseArgument = (context, argument) => {
if (argument.type === 'Identifier') {
return argument.name;
}
return context.getSourceCode().getText(arg);
return context.getSourceCode().getText(argument);
};

@@ -25,0 +25,0 @@

'use strict';
const getDocsUrl = require('./utils/get-docs-url');
const doesNotContain = (string, chars) => chars.every(char => !string.includes(char));
const doesNotContain = (string, characters) => characters.every(character => !string.includes(character));

@@ -40,3 +40,3 @@ const isSimpleString = string => doesNotContain(

node,
message: 'Prefer `String#startsWith` over a regex with `^`.'
message: 'Prefer `String#startsWith()` over a regex with `^`.'
});

@@ -46,3 +46,3 @@ } else if (pattern.endsWith('$') && isSimpleString(pattern.slice(0, -1))) {

node,
message: 'Prefer `String#endsWith` over a regex with `$`.'
message: 'Prefer `String#endsWith()` over a regex with `$`.'
});

@@ -49,0 +49,0 @@ }

'use strict';
const getDocsUrl = require('./utils/get-docs-url');
const message = 'Prefer `textContent` over `innerText`.';
const message = 'Prefer `.textContent` over `.innerText`.';

@@ -6,0 +6,0 @@ const create = context => {

@@ -255,7 +255,8 @@ 'use strict';

/*
* This function has terrible big O complexity, so we limit it by `limit`.
* This is fine since result of the function is used only to check if there is zero, one or more
* replacements and when formating the message.
* Example: `[[1, 2], [3, 4]]` -> `[[1, 3], [1, 4], [2, 3], [2, 4]]`
*/
This function has terrible big O complexity, so we limit it by `limit`.
This is fine since result of the function is used only to check if there is zero, one or more replacements and when formating the message.
Example: `[[1, 2], [3, 4]]` → `[[1, 3], [1, 4], [2, 3], [2, 4]]`
*/
const getWordByWordReplacementsCombinations = (wordByWordReplacements, limit = 16) => {

@@ -262,0 +263,0 @@ if (wordByWordReplacements.length === 0) {

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

message,
fix: fixer => fixer.replaceTextRange(node.range, `/${newPattern}/${flags}`)
fix: fixer => fixer.replaceText(node, `/${newPattern}/${flags}`)
});

@@ -38,5 +38,4 @@ }

let oldPattern = null;
let flags = null;
let oldPattern;
let flags;
if (hasRegExp) {

@@ -57,3 +56,3 @@ oldPattern = args[0].regex.pattern;

} else {
// Escape backslash and apostrophe because we wrap the result in single quotes.
// Escape backslash and apostrophe because we wrap the result in single quotes
fixed = (newPattern || '').replace(/\\/, '\\\\');

@@ -67,3 +66,3 @@ fixed = fixed.replace(/'/, '\'');

message,
fix: fixer => fixer.replaceTextRange(args[0].range, fixed)
fix: fixer => fixer.replaceText(args[0], fixed)
});

@@ -70,0 +69,0 @@ }

@@ -8,6 +8,6 @@ 'use strict';

ThrowStatement: node => {
const arg = node.argument;
const error = arg.callee;
const {argument} = node;
const error = argument.callee;
if (arg.type === 'CallExpression' && customError.test(error.name)) {
if (argument.type === 'CallExpression' && customError.test(error.name)) {
context.report({

@@ -14,0 +14,0 @@ node,

@@ -42,26 +42,25 @@ 'use strict';

/**
* Rule-specific name check function
*
* @callback isSafe
* @param {string} indexifiedName - The generated candidate name.
* @param {Scope[]} scopes - The same list of scopes you pass to `avoidCapture`.
* @return {boolean} - `true` if the `indexifiedName` is ok.
*/
Rule-specific name check function.
@callback isSafe
@param {string} indexifiedName - The generated candidate name.
@param {Scope[]} scopes - The same list of scopes you pass to `avoidCapture`.
@returns {boolean} - `true` if the `indexifiedName` is ok.
*/
/**
* Generates a unique name prefixed with `name` such that:
* - it is not defined in any of the `scopes`,
* - it is not a reserved word,
* - it is not `arguments` in strict scopes (where `arguments` is not allowed),
* - it does not collide with the actual `arguments` (which is always defined in function scopes).
*
* Useful when you want to rename a variable (or create a new variable)
* while being sure not to shadow any other variables in the code.
*
* @param {string} name - The desired name for a new variable.
* @param {Scope[]} scopes - The list of scopes the new variable will be referenced in.
* @param {number} ecmaVersion - The language version, get it from `context.parserOptions.ecmaVersion`.
* @param {isSafe} [isSafe] - Rule-specific name check function.
* @returns {string} - Either `name` as is, or a string like `${name}_` suffixed with undescores to make the name unique.
*/
Generates a unique name prefixed with `name` such that:
- it is not defined in any of the `scopes`,
- it is not a reserved word,
- it is not `arguments` in strict scopes (where `arguments` is not allowed),
- it does not collide with the actual `arguments` (which is always defined in function scopes).
Useful when you want to rename a variable (or create a new variable) while being sure not to shadow any other variables in the code.
@param {string} name - The desired name for a new variable.
@param {Scope[]} scopes - The list of scopes the new variable will be referenced in.
@param {number} ecmaVersion - The language version, get it from `context.parserOptions.ecmaVersion`.
@param {isSafe} [isSafe] - Rule-specific name check function.
@returns {string} - Either `name` as is, or a string like `${name}_` suffixed with undescores to make the name unique.
*/
module.exports = (name, scopes, ecmaVersion, isSafe = alwaysTrue) => {

@@ -68,0 +67,0 @@ const isStrict = someScopeIsStrict(scopes);

'use strict';
const path = require('path');
const pkg = require('../../package');
const packageJson = require('../../package');

@@ -9,3 +9,3 @@ const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';

const ruleName = path.basename(filename, '.js');
return `${repoUrl}/blob/v${pkg.version}/docs/rules/${ruleName}.md`;
return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`;
};
'use strict';
/**
* Finds a variable named `name` in the scope `scope` (or it's parents).
*
* @param {string} name - The variable name to be resolve.
* @param {Scope} scope - The scope to look for the variable in.
* @returns {?Variable} - The found variable, if any.
*/
Finds a variable named `name` in the scope `scope` (or it's parents).
@param {string} name - The variable name to be resolve.
@param {Scope} scope - The scope to look for the variable in.
@returns {Variable?} - The found variable, if any.
*/
module.exports = (name, scope) => {

@@ -11,0 +11,0 @@ while (scope) {

Sorry, the diff of this file is not supported yet

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