Enable unicorn/prefer-string-replace-all rule (#13788)
This commit is contained in:
1 parent
db43ab6409
commit
9eafbf6854
17 files changed
+107
-37
No files matched your search
@@ -5,13 +5,13 @@ Note:
|
||||
2. `postcss` contains `Container` class with `.at` method
|
||||
*/
|
||||
|
||||
const at = (isOptionalObject, object, index, ...args) => {
|
||||
const at = (isOptionalObject, object, index) => {
|
||||
if (isOptionalObject && (object === undefined || object === null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return object.at
|
||||
? object.at(index, ...args)
|
||||
? object.at(index)
|
||||
: object[index < 0 ? object.length + index : index];
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
const stringReplaceAll = (isOptionalObject, original, pattern, replacement) => {
|
||||
if (isOptionalObject && (original === undefined || original === null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (original.replaceAll) {
|
||||
return original.replaceAll(pattern, replacement);
|
||||
}
|
||||
|
||||
// Simple detection to check if pattern is a `RegExp`
|
||||
if (pattern.global) {
|
||||
return original.replace(pattern, replacement);
|
||||
}
|
||||
|
||||
// Doesn't work for substitutes, eg `.replaceAll("*", "\\$&")`
|
||||
return original.split(pattern).join(replacement);
|
||||
};
|
||||
|
||||
export default stringReplaceAll;
|
||||
@@ -7,6 +7,9 @@ import { SOURCE_DIR } from "../../utils/index.mjs";
|
||||
|
||||
const generate = babelGenerator.default;
|
||||
const atHelperPath = fileURLToPath(new URL("../shims/at.js", import.meta.url));
|
||||
const stringReplaceAllHelperPath = fileURLToPath(
|
||||
new URL("../shims/string-replace-all.js", import.meta.url)
|
||||
);
|
||||
|
||||
/* Doesn't work for dependencies, optional call, computed property, and spread arguments */
|
||||
|
||||
@@ -59,33 +62,40 @@ function transformObjectHasOwnCall(node) {
|
||||
* @param {import("@babel/types").Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function transformRelativeIndexingCall(node) {
|
||||
function transformMethodCall({
|
||||
node,
|
||||
method,
|
||||
replacement = `__${method}`,
|
||||
argumentsLength,
|
||||
}) {
|
||||
if (
|
||||
!(
|
||||
(node.type === "CallExpression" ||
|
||||
node.type === "OptionalCallExpression") &&
|
||||
!node.optional &&
|
||||
node.arguments.length === 1 &&
|
||||
node.arguments.length === argumentsLength &&
|
||||
node.arguments.every(({ type }) => type !== "SpreadElement") &&
|
||||
(node.callee.type === "MemberExpression" ||
|
||||
node.callee.type === "OptionalMemberExpression") &&
|
||||
!node.callee.computed &&
|
||||
node.callee.object.type !== "ThisExpression" &&
|
||||
node.callee.property.type === "Identifier" &&
|
||||
node.callee.property.name === "at"
|
||||
node.callee.property.name === method
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// `__at(isOptionalObject, object, ...arguments)`
|
||||
node.arguments.unshift(
|
||||
{
|
||||
type: "BooleanLiteral",
|
||||
value: node.callee.type === "OptionalMemberExpression",
|
||||
leadingComments: [{ type: "CommentBlock", value: " isOptionalObject" }],
|
||||
},
|
||||
node.callee.object
|
||||
);
|
||||
node.callee = { type: "Identifier", name: "__at" };
|
||||
node.callee = { type: "Identifier", name: replacement };
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -93,22 +103,40 @@ function transformRelativeIndexingCall(node) {
|
||||
function transform(original, file) {
|
||||
if (
|
||||
file === atHelperPath ||
|
||||
file === stringReplaceAllHelperPath ||
|
||||
!file.startsWith(SOURCE_DIR) ||
|
||||
(!original.includes(".at(") && !original.includes("Object.hasOwn("))
|
||||
(!original.includes(".at(") &&
|
||||
!original.includes(".replaceAll(") &&
|
||||
!original.includes("Object.hasOwn("))
|
||||
) {
|
||||
return original;
|
||||
}
|
||||
|
||||
let changed = false;
|
||||
let shouldInjectRelativeIndexingHelper = false;
|
||||
let shouldInjectStringReplaceAllHelperPath = false;
|
||||
|
||||
const ast = parse(original, { sourceType: "module" });
|
||||
traverse(ast, (node) => {
|
||||
const hasObjectHasOwnCall = transformObjectHasOwnCall(node);
|
||||
changed ||= hasObjectHasOwnCall;
|
||||
|
||||
const hasRelativeIndexingCall = transformRelativeIndexingCall(node);
|
||||
const hasRelativeIndexingCall = transformMethodCall({
|
||||
node,
|
||||
method: "at",
|
||||
argumentsLength: 1,
|
||||
});
|
||||
shouldInjectRelativeIndexingHelper ||= hasRelativeIndexingCall;
|
||||
changed ||= hasRelativeIndexingCall;
|
||||
|
||||
const hasStringReplaceAllCall = transformMethodCall({
|
||||
node,
|
||||
method: "replaceAll",
|
||||
replacement: "__stringReplaceAll",
|
||||
argumentsLength: 2,
|
||||
});
|
||||
shouldInjectStringReplaceAllHelperPath ||= hasStringReplaceAllCall;
|
||||
|
||||
changed ||=
|
||||
hasObjectHasOwnCall || hasRelativeIndexingCall || hasStringReplaceAllCall;
|
||||
});
|
||||
|
||||
if (!changed) {
|
||||
@@ -117,9 +145,22 @@ function transform(original, file) {
|
||||
|
||||
let { code } = generate(ast);
|
||||
|
||||
if (shouldInjectRelativeIndexingHelper) {
|
||||
const helpers = [
|
||||
shouldInjectRelativeIndexingHelper && { name: "__at", path: atHelperPath },
|
||||
shouldInjectStringReplaceAllHelperPath && {
|
||||
name: "__stringReplaceAll",
|
||||
path: stringReplaceAllHelperPath,
|
||||
},
|
||||
]
|
||||
.filter(Boolean)
|
||||
.map(
|
||||
(helper) => `import ${helper.name} from ${JSON.stringify(helper.path)};`
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
if (helpers) {
|
||||
code = outdent`
|
||||
import __at from ${JSON.stringify(atHelperPath)};
|
||||
${helpers}
|
||||
|
||||
${code}
|
||||
`;
|
||||
|
||||
@@ -25,7 +25,7 @@ async function update() {
|
||||
.match(
|
||||
/<svg.*?octicon-code-square.*?>.*?<\/svg>\s*([\d,]+)\s*Repositories\s*<\/a>/
|
||||
)[1]
|
||||
.replace(/,/g, "")
|
||||
.replaceAll(",", "")
|
||||
);
|
||||
if (Number.isNaN(dependentsCountNpm)) {
|
||||
throw new TypeError(
|
||||
|
||||
@@ -32,7 +32,7 @@ module.exports = {
|
||||
return;
|
||||
}
|
||||
|
||||
const fixed = name.replace(/JSX/g, "Jsx");
|
||||
const fixed = name.replaceAll("JSX", "Jsx");
|
||||
context.report({
|
||||
node,
|
||||
messageId: MESSAGE_ID,
|
||||
|
||||
Reference in new issue
Block a user