@stylistic/eslint-plugin-js
Version:
JavaScript stylistic rules for ESLint, migrated from [eslint core](https://github.com/eslint/eslint).
146 lines (143 loc) • 4.95 kB
JavaScript
import { c as createRule, e as isOpeningParenToken, r as isNotQuestionDotToken, L as LINEBREAK_MATCHER } from '../utils.js';
import 'eslint-visitor-keys';
import 'espree';
var functionCallSpacing = createRule({
name: "function-call-spacing",
package: "js",
meta: {
type: "layout",
docs: {
description: "Require or disallow spacing between function identifiers and their invocations"
},
fixable: "whitespace",
schema: {
anyOf: [
{
type: "array",
items: [
{
type: "string",
enum: ["never"]
}
],
minItems: 0,
maxItems: 1
},
{
type: "array",
items: [
{
type: "string",
enum: ["always"]
},
{
type: "object",
properties: {
allowNewlines: {
type: "boolean"
}
},
additionalProperties: false
}
],
minItems: 0,
maxItems: 2
}
]
},
messages: {
unexpectedWhitespace: "Unexpected whitespace between function name and paren.",
unexpectedNewline: "Unexpected newline between function name and paren.",
missing: "Missing space between function name and paren."
}
},
create(context) {
const never = context.options[0] !== "always";
const allowNewlines = !never && context.options[1] && context.options[1].allowNewlines;
const sourceCode = context.sourceCode;
const text = sourceCode.getText();
function checkSpacing(node, leftToken, rightToken) {
const textBetweenTokens = text.slice(leftToken.range[1], rightToken.range[0]).replace(/\/\*.*?\*\//gu, "");
const hasWhitespace = /\s/u.test(textBetweenTokens);
const hasNewline = hasWhitespace && LINEBREAK_MATCHER.test(textBetweenTokens);
if (never && hasWhitespace) {
context.report({
node,
loc: {
start: leftToken.loc.end,
end: {
line: rightToken.loc.start.line,
column: rightToken.loc.start.column - 1
}
},
messageId: "unexpectedWhitespace",
fix(fixer) {
if (sourceCode.commentsExistBetween(leftToken, rightToken))
return null;
if ("optional" in node && node.optional)
return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], "?.");
if (hasNewline)
return null;
return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
}
});
} else if (!never && !hasWhitespace) {
context.report({
node,
loc: {
start: {
line: leftToken.loc.end.line,
column: leftToken.loc.end.column - 1
},
end: rightToken.loc.start
},
messageId: "missing",
fix(fixer) {
if ("optional" in node && node.optional)
return null;
return fixer.insertTextBefore(rightToken, " ");
}
});
} else if (!never && !allowNewlines && hasNewline) {
context.report({
node,
loc: {
start: leftToken.loc.end,
end: rightToken.loc.start
},
messageId: "unexpectedNewline",
fix(fixer) {
if (!("optional" in node) || !node.optional)
return null;
if (sourceCode.commentsExistBetween(leftToken, rightToken))
return null;
const range = [leftToken.range[1], rightToken.range[0]];
const qdToken = sourceCode.getTokenAfter(leftToken);
if (qdToken.range[0] === leftToken.range[1])
return fixer.replaceTextRange(range, "?. ");
if (qdToken.range[1] === rightToken.range[0])
return fixer.replaceTextRange(range, " ?.");
return fixer.replaceTextRange(range, " ?. ");
}
});
}
}
return {
"CallExpression, NewExpression": function(node) {
const lastToken = sourceCode.getLastToken(node);
const lastCalleeToken = sourceCode.getLastToken(node.callee);
const parenToken = sourceCode.getFirstTokenBetween(lastCalleeToken, lastToken, isOpeningParenToken);
const prevToken = parenToken && sourceCode.getTokenBefore(parenToken, isNotQuestionDotToken);
if (!(parenToken && parenToken.range[1] < node.range[1]))
return;
checkSpacing(node, prevToken, parenToken);
},
ImportExpression(node) {
const leftToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getTokenAfter(leftToken);
checkSpacing(node, leftToken, rightToken);
}
};
}
});
export { functionCallSpacing as default };