* Fix paid organization creation limit * Clarify stack PR URL reporting * Clarify clickable stack PR links
Showing the changes to scripts (2 of 14 files). Show all
Unified · Split
| @@ -27,6 +27,7 @@ import noUnknownErrorMessage from "./oxlint-plugin-executor/rules/no-unknown-err · 26 unmodified lines | |||
| 27 | import noUnknownShapeProbing from "./oxlint-plugin-executor/rules/no-unknown-shape-probing.js"; | 27 | import noUnknownShapeProbing from "./oxlint-plugin-executor/rules/no-unknown-shape-probing.js"; |
| 28 | import noUnsupportedEffectApi from "./oxlint-plugin-executor/rules/no-unsupported-effect-api.js"; | 28 | import noUnsupportedEffectApi from "./oxlint-plugin-executor/rules/no-unsupported-effect-api.js"; |
| 29 | import noVitestImport from "./oxlint-plugin-executor/rules/no-vitest-import.js"; | 29 | import noVitestImport from "./oxlint-plugin-executor/rules/no-vitest-import.js"; |
| 30 | import preferEffectPredicate from "./oxlint-plugin-executor/rules/prefer-effect-predicate.js"; | ||
| 30 | import preferSchemaInferredTypes from "./oxlint-plugin-executor/rules/prefer-schema-inferred-types.js"; | 31 | import preferSchemaInferredTypes from "./oxlint-plugin-executor/rules/prefer-schema-inferred-types.js"; |
| 31 | import preferYieldTaggedError from "./oxlint-plugin-executor/rules/prefer-yield-tagged-error.js"; | 32 | import preferYieldTaggedError from "./oxlint-plugin-executor/rules/prefer-yield-tagged-error.js"; |
| 32 | import preferValueInferredExtensionTypes from "./oxlint-plugin-executor/rules/prefer-value-inferred-extension-types.js"; | 33 | import preferValueInferredExtensionTypes from "./oxlint-plugin-executor/rules/prefer-value-inferred-extension-types.js"; |
| @@ -67,6 +68,7 @@ export default { · 34 unmodified lines | |||
| 67 | "no-unknown-error-message": noUnknownErrorMessage, | 68 | "no-unknown-error-message": noUnknownErrorMessage, |
| 68 | "no-unknown-shape-probing": noUnknownShapeProbing, | 69 | "no-unknown-shape-probing": noUnknownShapeProbing, |
| 69 | "no-unsupported-effect-api": noUnsupportedEffectApi, | 70 | "no-unsupported-effect-api": noUnsupportedEffectApi, |
| 71 | "prefer-effect-predicate": preferEffectPredicate, | ||
| 70 | "prefer-schema-inferred-types": preferSchemaInferredTypes, | 72 | "prefer-schema-inferred-types": preferSchemaInferredTypes, |
| 71 | "prefer-value-inferred-extension-types": preferValueInferredExtensionTypes, | 73 | "prefer-value-inferred-extension-types": preferValueInferredExtensionTypes, |
| 72 | "prefer-yield-tagged-error": preferYieldTaggedError, | 74 | "prefer-yield-tagged-error": preferYieldTaggedError, |
| @@ -0,0 +1,89 @@ | |||
| 1 | import { getPropertyName, isIdentifier, unwrapExpression } from "../utils.js"; | ||
| 2 | |||
| 3 | const message = | ||
| 4 | "Use Predicate.isNotNull/isNotUndefined/isNotNullish from effect instead of hand-rolled nullish predicates."; | ||
| 5 | |||
| 6 | const nullishOperators = new Set(["!==", "!=", "===", "=="]); | ||
| 7 | |||
| 8 | const isNullLiteral = (node) => node?.type === "Literal" && node.value === null; | ||
| 9 | const isUndefinedIdentifier = (node) => isIdentifier(node, "undefined"); | ||
| 10 | const isNullishLiteral = (node) => isNullLiteral(node) || isUndefinedIdentifier(node); | ||
| 11 | |||
| 12 | const isNullishComparison = (node, identifierName) => { | ||
| 13 | const expression = unwrapExpression(node); | ||
| 14 | if (expression?.type !== "BinaryExpression" || !nullishOperators.has(expression.operator)) { | ||
| 15 | return false; | ||
| 16 | } | ||
| 17 | |||
| 18 | const left = unwrapExpression(expression.left); | ||
| 19 | const right = unwrapExpression(expression.right); | ||
| 20 | return ( | ||
| 21 | (isIdentifier(left, identifierName) && isNullishLiteral(right)) || | ||
| 22 | (isIdentifier(right, identifierName) && isNullishLiteral(left)) | ||
| 23 | ); | ||
| 24 | }; | ||
| 25 | |||
| 26 | const getSingleIdentifierParamName = (params) => { | ||
| 27 | if (params.length !== 1) return undefined; | ||
| 28 | const param = unwrapExpression(params[0]); | ||
| 29 | return param?.type === "Identifier" ? param.name : undefined; | ||
| 30 | }; | ||
| 31 | |||
| 32 | const isNullishPredicateFunction = (node) => { | ||
| 33 | const name = getSingleIdentifierParamName(node.params ?? []); | ||
| 34 | return name !== undefined && isNullishComparison(node.body, name); | ||
| 35 | }; | ||
| 36 | |||
| 37 | const isFilterCall = (node) => { | ||
| 38 | const callee = unwrapExpression(node.callee); | ||
| 39 | return callee?.type === "MemberExpression" && getPropertyName(callee.property) === "filter"; | ||
| 40 | }; | ||
| 41 | |||
| 42 | const importsEffect = (node) => { | ||
| 43 | const source = node.source; | ||
| 44 | return source?.type === "Literal" && source.value === "effect"; | ||
| 45 | }; | ||
| 46 | |||
| 47 | export default { | ||
| 48 | meta: { | ||
| 49 | type: "problem", | ||
| 50 | docs: { | ||
| 51 | description: message, | ||
| 52 | }, | ||
| 53 | }, | ||
| 54 | create(context) { | ||
| 55 | let hasEffectImport = false; | ||
| 56 | |||
| 57 | return { | ||
| 58 | ImportDeclaration(node) { | ||
| 59 | if (importsEffect(node)) { | ||
| 60 | hasEffectImport = true; | ||
| 61 | } | ||
| 62 | }, | ||
| 63 | VariableDeclarator(node) { | ||
| 64 | if (!hasEffectImport) return; | ||
| 65 | const init = unwrapExpression(node.init); | ||
| 66 | if (init?.type === "ArrowFunctionExpression" && isNullishPredicateFunction(init)) { | ||
| 67 | context.report({ node: init, message }); | ||
| 68 | } | ||
| 69 | }, | ||
| 70 | FunctionDeclaration(node) { | ||
| 71 | if (!hasEffectImport) return; | ||
| 72 | if (isNullishPredicateFunction(node)) { | ||
| 73 | context.report({ node, message }); | ||
| 74 | } | ||
| 75 | }, | ||
| 76 | CallExpression(node) { | ||
| 77 | if (!hasEffectImport || !isFilterCall(node)) return; | ||
| 78 | const predicate = unwrapExpression(node.arguments[0]); | ||
| 79 | if ( | ||
| 80 | (predicate?.type === "ArrowFunctionExpression" || | ||
| 81 | predicate?.type === "FunctionExpression") && | ||
| 82 | isNullishPredicateFunction(predicate) | ||
| 83 | ) { | ||
| 84 | context.report({ node: predicate, message }); | ||
| 85 | } | ||
| 86 | }, | ||
| 87 | }; | ||
| 88 | }, | ||
| 89 | }; | ||