@stll/oxlint-plugin 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/no-any-casts.cjs.map +1 -1
- package/dist/no-dangerous-type-assertions.cjs.map +1 -1
- package/dist/no-partial-record-satisfies.cjs.map +1 -1
- package/dist/no-partial-record-satisfies.mjs +1 -1
- package/dist/no-raw-route-query-client.cjs.map +1 -1
- package/dist/no-raw-route-query-client.mjs +1 -1
- package/dist/no-unsafe-inner-html.cjs +458 -66
- package/dist/no-unsafe-inner-html.cjs.map +1 -1
- package/dist/no-unsafe-inner-html.d.cts +106 -1
- package/dist/no-unsafe-inner-html.d.mts +105 -1
- package/dist/no-unsafe-inner-html.mjs +458 -68
- package/dist/no-unsafe-inner-html.mjs.map +1 -1
- package/dist/require-loader-prefetch.cjs +8 -7
- package/dist/require-loader-prefetch.cjs.map +1 -1
- package/dist/require-loader-prefetch.mjs +8 -7
- package/dist/require-loader-prefetch.mjs.map +1 -1
- package/dist/utils.cjs +85 -10
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.mjs +54 -9
- package/dist/utils.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-any-casts.cjs","names":[],"sources":["../src/no-any-casts.ts"],"sourcesContent":["// Disallow `as any` and `<any>` casts.\n//\n// Distinct from `no-explicit-any` (which targets `: any` annotations\n// in declarations). This rule catches the cast form — typically\n// `value as any` or the laundering `value as any as Target` — which\n// bypasses brand checks, discriminated-union narrowing, and every\n// other safety the type system provides.\n\nimport { eslintCompatPlugin } from \"@oxlint/plugins\";\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-any-casts\" },\n rules: {\n \"no-any-casts\": {\n meta: {\n type: \"problem\",\n messages: {\n noAnyCast:\n \"Avoid `as any` casts. They bypass branded IDs and \" +\n \"discriminated-union narrowing. Narrow with a type guard, \" +\n \"use `unknown` + a guard, or refactor the source so the \" +\n \"cast isn't needed.\",\n },\n },\n createOnce(context) {\n function check(node) {\n if (node.typeAnnotation?.type === \"TSAnyKeyword\") {\n context.report({ node, messageId: \"noAnyCast\" });\n }\n }\n return {\n TSAsExpression: check,\n TSTypeAssertion: check,\n };\n },\n },\n },\n});\n"],"mappings":";;;;;AAUA,IAAA,wBAAA,
|
|
1
|
+
{"version":3,"file":"no-any-casts.cjs","names":["eslintCompatPlugin"],"sources":["../src/no-any-casts.ts"],"sourcesContent":["// Disallow `as any` and `<any>` casts.\n//\n// Distinct from `no-explicit-any` (which targets `: any` annotations\n// in declarations). This rule catches the cast form — typically\n// `value as any` or the laundering `value as any as Target` — which\n// bypasses brand checks, discriminated-union narrowing, and every\n// other safety the type system provides.\n\nimport { eslintCompatPlugin } from \"@oxlint/plugins\";\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-any-casts\" },\n rules: {\n \"no-any-casts\": {\n meta: {\n type: \"problem\",\n messages: {\n noAnyCast:\n \"Avoid `as any` casts. They bypass branded IDs and \" +\n \"discriminated-union narrowing. Narrow with a type guard, \" +\n \"use `unknown` + a guard, or refactor the source so the \" +\n \"cast isn't needed.\",\n },\n },\n createOnce(context) {\n function check(node) {\n if (node.typeAnnotation?.type === \"TSAnyKeyword\") {\n context.report({ node, messageId: \"noAnyCast\" });\n }\n }\n return {\n TSAsExpression: check,\n TSTypeAssertion: check,\n };\n },\n },\n },\n});\n"],"mappings":";;;;;AAUA,IAAA,wBAAA,4BAAeA,CAAAA,CAAAA,mBAAAA,CAAmB;CAChC,MAAM,EAAE,MAAM,eAAe;CAC7B,OAAO,EACL,gBAAgB;EACd,MAAM;GACJ,MAAM;GACN,UAAU,EACR,WACE,uLAIJ;EACF;EACA,WAAW,SAAS;GAClB,SAAS,MAAM,MAAM;IACnB,IAAI,KAAK,gBAAgB,SAAS,gBAChC,QAAQ,OAAO;KAAE;KAAM,WAAW;IAAY,CAAC;GAEnD;GACA,OAAO;IACL,gBAAgB;IAChB,iBAAiB;GACnB;EACF;CACF,EACF;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-dangerous-type-assertions.cjs","names":[],"sources":["../src/no-dangerous-type-assertions.ts"],"sourcesContent":["// Disallow object-literal casts: `{...} as T`, `<T>{...}`.\n//\n// Casting an object literal to a type silently hides missing required\n// fields — the type system would otherwise catch the omission. Use a\n// typed binding (`const x: T = { ... }`) or `satisfies T` so missing\n// fields surface as type errors.\n//\n// Allows `as const` (legitimate widening control).\n// Allows `as any` / `as unknown` (those have dedicated rules / are\n// often used as the first step of an explicit launder).\n\nimport { eslintCompatPlugin } from \"@oxlint/plugins\";\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-dangerous-type-assertions\" },\n rules: {\n \"no-dangerous-type-assertions\": {\n meta: {\n type: \"problem\",\n messages: {\n noObjectLiteralCast:\n \"Don't cast an object literal with `as`. Type the binding \" +\n \"(`const x: T = { ... }`) or use `satisfies T` so missing \" +\n \"required fields fail typecheck.\",\n },\n },\n createOnce(context) {\n function unwrapExpression(expression) {\n let current = expression;\n while (\n current?.type === \"ParenthesizedExpression\" ||\n current?.type === \"TSAsExpression\" ||\n current?.type === \"TSTypeAssertion\" ||\n current?.type === \"TSNonNullExpression\" ||\n current?.type === \"TSSatisfiesExpression\"\n ) {\n current = current.expression;\n }\n return current;\n }\n\n function check(node) {\n const expression = unwrapExpression(node.expression);\n if (expression?.type !== \"ObjectExpression\") {\n return;\n }\n const ann = node.typeAnnotation;\n if (!ann) {\n return;\n }\n // Allow `as const`\n if (\n ann.type === \"TSTypeReference\" &&\n ann.typeName?.type === \"Identifier\" &&\n ann.typeName.name === \"const\"\n ) {\n return;\n }\n // `as any` and `as unknown` have their own rules / are\n // typically the laundering step, not the final shape claim.\n if (ann.type === \"TSAnyKeyword\" || ann.type === \"TSUnknownKeyword\") {\n return;\n }\n context.report({ node, messageId: \"noObjectLiteralCast\" });\n }\n return {\n TSAsExpression: check,\n TSTypeAssertion: check,\n };\n },\n },\n },\n});\n"],"mappings":";;;;;AAaA,IAAA,wCAAA,
|
|
1
|
+
{"version":3,"file":"no-dangerous-type-assertions.cjs","names":["eslintCompatPlugin"],"sources":["../src/no-dangerous-type-assertions.ts"],"sourcesContent":["// Disallow object-literal casts: `{...} as T`, `<T>{...}`.\n//\n// Casting an object literal to a type silently hides missing required\n// fields — the type system would otherwise catch the omission. Use a\n// typed binding (`const x: T = { ... }`) or `satisfies T` so missing\n// fields surface as type errors.\n//\n// Allows `as const` (legitimate widening control).\n// Allows `as any` / `as unknown` (those have dedicated rules / are\n// often used as the first step of an explicit launder).\n\nimport { eslintCompatPlugin } from \"@oxlint/plugins\";\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-dangerous-type-assertions\" },\n rules: {\n \"no-dangerous-type-assertions\": {\n meta: {\n type: \"problem\",\n messages: {\n noObjectLiteralCast:\n \"Don't cast an object literal with `as`. Type the binding \" +\n \"(`const x: T = { ... }`) or use `satisfies T` so missing \" +\n \"required fields fail typecheck.\",\n },\n },\n createOnce(context) {\n function unwrapExpression(expression) {\n let current = expression;\n while (\n current?.type === \"ParenthesizedExpression\" ||\n current?.type === \"TSAsExpression\" ||\n current?.type === \"TSTypeAssertion\" ||\n current?.type === \"TSNonNullExpression\" ||\n current?.type === \"TSSatisfiesExpression\"\n ) {\n current = current.expression;\n }\n return current;\n }\n\n function check(node) {\n const expression = unwrapExpression(node.expression);\n if (expression?.type !== \"ObjectExpression\") {\n return;\n }\n const ann = node.typeAnnotation;\n if (!ann) {\n return;\n }\n // Allow `as const`\n if (\n ann.type === \"TSTypeReference\" &&\n ann.typeName?.type === \"Identifier\" &&\n ann.typeName.name === \"const\"\n ) {\n return;\n }\n // `as any` and `as unknown` have their own rules / are\n // typically the laundering step, not the final shape claim.\n if (ann.type === \"TSAnyKeyword\" || ann.type === \"TSUnknownKeyword\") {\n return;\n }\n context.report({ node, messageId: \"noObjectLiteralCast\" });\n }\n return {\n TSAsExpression: check,\n TSTypeAssertion: check,\n };\n },\n },\n },\n});\n"],"mappings":";;;;;AAaA,IAAA,wCAAA,4BAAeA,CAAAA,CAAAA,mBAAAA,CAAmB;CAChC,MAAM,EAAE,MAAM,+BAA+B;CAC7C,OAAO,EACL,gCAAgC;EAC9B,MAAM;GACJ,MAAM;GACN,UAAU,EACR,qBACE,oJAGJ;EACF;EACA,WAAW,SAAS;GAClB,SAAS,iBAAiB,YAAY;IACpC,IAAI,UAAU;IACd,OACE,SAAS,SAAS,6BAClB,SAAS,SAAS,oBAClB,SAAS,SAAS,qBAClB,SAAS,SAAS,yBAClB,SAAS,SAAS,yBAElB,UAAU,QAAQ;IAEpB,OAAO;GACT;GAEA,SAAS,MAAM,MAAM;IAEnB,IADmB,iBAAiB,KAAK,UAC5B,CAAC,EAAE,SAAS,oBACvB;IAEF,MAAM,MAAM,KAAK;IACjB,IAAI,CAAC,KACH;IAGF,IACE,IAAI,SAAS,qBACb,IAAI,UAAU,SAAS,gBACvB,IAAI,SAAS,SAAS,SAEtB;IAIF,IAAI,IAAI,SAAS,kBAAkB,IAAI,SAAS,oBAC9C;IAEF,QAAQ,OAAO;KAAE;KAAM,WAAW;IAAsB,CAAC;GAC3D;GACA,OAAO;IACL,gBAAgB;IAChB,iBAAiB;GACnB;EACF;CACF,EACF;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-partial-record-satisfies.cjs","names":["isIdentifier"],"sources":["../src/no-partial-record-satisfies.ts"],"sourcesContent":["import { eslintCompatPlugin } from \"@oxlint/plugins\";\n// Ban `<object literal> satisfies Partial<Record<Union, T>>` (with or\n// without a leading `as const`).\n//\n// A const object literal pinned with `satisfies` against a `Record` keyed by\n// a union declares itself the classification of every union member —\n// `satisfies` fails typecheck the moment a new member is added and left\n// unhandled. Wrapping that `Record` in `Partial` cancels the guarantee: a\n// missing member typechecks silently, so the literal can drift out of sync\n// with the union with no compiler signal. That silent-drift surface can cause\n// a classification-table bug when a newly added member falls through a\n// `Partial<Record<...>>` lookup instead of failing typecheck.\n//\n// `Readonly<...>` wrapping either side (`Readonly<Partial<Record<...>>>` or\n// `Partial<Readonly<Record<...>>>`) is unwrapped before the check, since it\n// changes mutability, not totality.\n//\n// Only the `satisfies` expression on an object literal is flagged. Plain\n// type-annotation positions (`const x: Partial<Record<...>> = {...}`),\n// function parameters, and variable/return type annotations are exempt:\n// those are legitimate uses (override inputs, accumulators, genuinely sparse\n// data) and carry no compiler guarantee of totality to lose.\n//\n// Flagged:\n// const x = {\n// a: 1,\n// } as const satisfies Partial<Record<Union, number>>;\n// const y = { a: 1 } satisfies Partial<Record<Union, number>>;\n// const z = {\n// a: 1,\n// } as const satisfies Readonly<Partial<Record<Union, number>>>;\n//\n// Allowed:\n// const x = {\n// a: 1,\n// } as const satisfies Record<Union, number>;\n// const fn = (overrides: Partial<Record<Union, number>>) => overrides;\n// let acc: Partial<Record<Union, number>> = {};\n// type Sparse = Partial<Record<Union, number>>;\n//\n// Fix by making the record total over the union — an explicit \"none\" /\n// `false` / `null` value for members where nothing applies forces a new\n// union member to be classified before it typechecks. If only a subset of\n// the union is ever relevant, derive a narrower union for the keys instead\n// of falling back to `Partial`. For genuinely sparse data where absence has\n// documented meaning (e.g. an unbounded key space), add an eslint-disable\n// with a comment naming what absence means.\n\nimport { isIdentifier } from \"./utils.ts\";\n\nconst unwrapReadonlyType = (typeNode) => {\n if (\n typeNode?.type === \"TSTypeReference\" &&\n isIdentifier(typeNode.typeName, \"Readonly\")\n ) {\n return typeNode.typeArguments?.params?.at(0) ?? null;\n }\n return typeNode;\n};\n\n// Matches `Partial<Record<...>>`, unwrapping a `Readonly<...>` wrapper on\n// either the outer (`Readonly<Partial<Record<...>>>`) or inner\n// (`Partial<Readonly<Record<...>>>`) type.\nconst isPartialRecordType = (typeNode) => {\n const outer = unwrapReadonlyType(typeNode);\n if (\n outer?.type !== \"TSTypeReference\" ||\n !isIdentifier(outer.typeName, \"Partial\")\n ) {\n return false;\n }\n const inner = unwrapReadonlyType(outer.typeArguments?.params?.at(0) ?? null);\n return (\n inner?.type === \"TSTypeReference\" && isIdentifier(inner.typeName, \"Record\")\n );\n};\n\n// Matches an object literal, or an object literal wrapped in `as const`.\nconst isObjectLiteralExpression = (node) => {\n if (node?.type === \"ObjectExpression\") {\n return true;\n }\n if (\n node?.type === \"TSAsExpression\" &&\n node.typeAnnotation?.type === \"TSTypeReference\" &&\n isIdentifier(node.typeAnnotation.typeName, \"const\")\n ) {\n return isObjectLiteralExpression(node.expression);\n }\n return false;\n};\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-partial-record-satisfies\" },\n rules: {\n \"no-partial-record-satisfies\": {\n meta: {\n type: \"problem\",\n messages: {\n noPartialRecordSatisfies:\n \"Don't pin an object literal with `satisfies Partial<Record<...>>` \" +\n \"— Partial cancels the totality check satisfies would otherwise \" +\n \"give you, so a union member can silently fall through. Make the \" +\n \"record total (explicit 'none'/false/null per member), narrow the \" +\n \"key union, or add an eslint-disable naming what absence means \" +\n \"for genuinely sparse data.\",\n },\n },\n createOnce(context) {\n return {\n TSSatisfiesExpression(node) {\n if (!isPartialRecordType(node.typeAnnotation)) {\n return;\n }\n if (!isObjectLiteralExpression(node.expression)) {\n return;\n }\n context.report({ node, messageId: \"noPartialRecordSatisfies\" });\n },\n };\n },\n },\n },\n});\n"],"mappings":";;;;;;;AAkDA,MAAM,sBAAsB,aAAa;CACvC,IACE,UAAU,SAAS,qBACnBA,cAAAA,aAAa,SAAS,UAAU,UAAU,GAE1C,OAAO,SAAS,eAAe,QAAQ,GAAG,CAAC,KAAK;CAElD,OAAO;AACT;AAKA,MAAM,uBAAuB,aAAa;CACxC,MAAM,QAAQ,mBAAmB,QAAQ;CACzC,IACE,OAAO,SAAS,qBAChB,CAACA,cAAAA,aAAa,MAAM,UAAU,SAAS,GAEvC,OAAO;CAET,MAAM,QAAQ,mBAAmB,MAAM,eAAe,QAAQ,GAAG,CAAC,KAAK,IAAI;CAC3E,OACE,OAAO,SAAS,qBAAqBA,cAAAA,aAAa,MAAM,UAAU,QAAQ;AAE9E;AAGA,MAAM,6BAA6B,SAAS;CAC1C,IAAI,MAAM,SAAS,oBACjB,OAAO;CAET,IACE,MAAM,SAAS,oBACf,KAAK,gBAAgB,SAAS,qBAC9BA,cAAAA,aAAa,KAAK,eAAe,UAAU,OAAO,GAElD,OAAO,0BAA0B,KAAK,UAAU;CAElD,OAAO;AACT;AAEA,IAAA,uCAAA,
|
|
1
|
+
{"version":3,"file":"no-partial-record-satisfies.cjs","names":["isIdentifier","eslintCompatPlugin"],"sources":["../src/no-partial-record-satisfies.ts"],"sourcesContent":["import { eslintCompatPlugin } from \"@oxlint/plugins\";\n// Ban `<object literal> satisfies Partial<Record<Union, T>>` (with or\n// without a leading `as const`).\n//\n// A const object literal pinned with `satisfies` against a `Record` keyed by\n// a union declares itself the classification of every union member —\n// `satisfies` fails typecheck the moment a new member is added and left\n// unhandled. Wrapping that `Record` in `Partial` cancels the guarantee: a\n// missing member typechecks silently, so the literal can drift out of sync\n// with the union with no compiler signal. That silent-drift surface can cause\n// a classification-table bug when a newly added member falls through a\n// `Partial<Record<...>>` lookup instead of failing typecheck.\n//\n// `Readonly<...>` wrapping either side (`Readonly<Partial<Record<...>>>` or\n// `Partial<Readonly<Record<...>>>`) is unwrapped before the check, since it\n// changes mutability, not totality.\n//\n// Only the `satisfies` expression on an object literal is flagged. Plain\n// type-annotation positions (`const x: Partial<Record<...>> = {...}`),\n// function parameters, and variable/return type annotations are exempt:\n// those are legitimate uses (override inputs, accumulators, genuinely sparse\n// data) and carry no compiler guarantee of totality to lose.\n//\n// Flagged:\n// const x = {\n// a: 1,\n// } as const satisfies Partial<Record<Union, number>>;\n// const y = { a: 1 } satisfies Partial<Record<Union, number>>;\n// const z = {\n// a: 1,\n// } as const satisfies Readonly<Partial<Record<Union, number>>>;\n//\n// Allowed:\n// const x = {\n// a: 1,\n// } as const satisfies Record<Union, number>;\n// const fn = (overrides: Partial<Record<Union, number>>) => overrides;\n// let acc: Partial<Record<Union, number>> = {};\n// type Sparse = Partial<Record<Union, number>>;\n//\n// Fix by making the record total over the union — an explicit \"none\" /\n// `false` / `null` value for members where nothing applies forces a new\n// union member to be classified before it typechecks. If only a subset of\n// the union is ever relevant, derive a narrower union for the keys instead\n// of falling back to `Partial`. For genuinely sparse data where absence has\n// documented meaning (e.g. an unbounded key space), add an eslint-disable\n// with a comment naming what absence means.\n\nimport { isIdentifier } from \"./utils.ts\";\n\nconst unwrapReadonlyType = (typeNode) => {\n if (\n typeNode?.type === \"TSTypeReference\" &&\n isIdentifier(typeNode.typeName, \"Readonly\")\n ) {\n return typeNode.typeArguments?.params?.at(0) ?? null;\n }\n return typeNode;\n};\n\n// Matches `Partial<Record<...>>`, unwrapping a `Readonly<...>` wrapper on\n// either the outer (`Readonly<Partial<Record<...>>>`) or inner\n// (`Partial<Readonly<Record<...>>>`) type.\nconst isPartialRecordType = (typeNode) => {\n const outer = unwrapReadonlyType(typeNode);\n if (\n outer?.type !== \"TSTypeReference\" ||\n !isIdentifier(outer.typeName, \"Partial\")\n ) {\n return false;\n }\n const inner = unwrapReadonlyType(outer.typeArguments?.params?.at(0) ?? null);\n return (\n inner?.type === \"TSTypeReference\" && isIdentifier(inner.typeName, \"Record\")\n );\n};\n\n// Matches an object literal, or an object literal wrapped in `as const`.\nconst isObjectLiteralExpression = (node) => {\n if (node?.type === \"ObjectExpression\") {\n return true;\n }\n if (\n node?.type === \"TSAsExpression\" &&\n node.typeAnnotation?.type === \"TSTypeReference\" &&\n isIdentifier(node.typeAnnotation.typeName, \"const\")\n ) {\n return isObjectLiteralExpression(node.expression);\n }\n return false;\n};\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-partial-record-satisfies\" },\n rules: {\n \"no-partial-record-satisfies\": {\n meta: {\n type: \"problem\",\n messages: {\n noPartialRecordSatisfies:\n \"Don't pin an object literal with `satisfies Partial<Record<...>>` \" +\n \"— Partial cancels the totality check satisfies would otherwise \" +\n \"give you, so a union member can silently fall through. Make the \" +\n \"record total (explicit 'none'/false/null per member), narrow the \" +\n \"key union, or add an eslint-disable naming what absence means \" +\n \"for genuinely sparse data.\",\n },\n },\n createOnce(context) {\n return {\n TSSatisfiesExpression(node) {\n if (!isPartialRecordType(node.typeAnnotation)) {\n return;\n }\n if (!isObjectLiteralExpression(node.expression)) {\n return;\n }\n context.report({ node, messageId: \"noPartialRecordSatisfies\" });\n },\n };\n },\n },\n },\n});\n"],"mappings":";;;;;;;AAkDA,MAAM,sBAAsB,aAAa;CACvC,IACE,UAAU,SAAS,qBACnBA,cAAAA,aAAa,SAAS,UAAU,UAAU,GAE1C,OAAO,SAAS,eAAe,QAAQ,GAAG,CAAC,KAAK;CAElD,OAAO;AACT;AAKA,MAAM,uBAAuB,aAAa;CACxC,MAAM,QAAQ,mBAAmB,QAAQ;CACzC,IACE,OAAO,SAAS,qBAChB,CAACA,cAAAA,aAAa,MAAM,UAAU,SAAS,GAEvC,OAAO;CAET,MAAM,QAAQ,mBAAmB,MAAM,eAAe,QAAQ,GAAG,CAAC,KAAK,IAAI;CAC3E,OACE,OAAO,SAAS,qBAAqBA,cAAAA,aAAa,MAAM,UAAU,QAAQ;AAE9E;AAGA,MAAM,6BAA6B,SAAS;CAC1C,IAAI,MAAM,SAAS,oBACjB,OAAO;CAET,IACE,MAAM,SAAS,oBACf,KAAK,gBAAgB,SAAS,qBAC9BA,cAAAA,aAAa,KAAK,eAAe,UAAU,OAAO,GAElD,OAAO,0BAA0B,KAAK,UAAU;CAElD,OAAO;AACT;AAEA,IAAA,uCAAA,GAAeC,gBAAAA,mBAAAA,CAAmB;CAChC,MAAM,EAAE,MAAM,8BAA8B;CAC5C,OAAO,EACL,+BAA+B;EAC7B,MAAM;GACJ,MAAM;GACN,UAAU,EACR,0BACE,6VAMJ;EACF;EACA,WAAW,SAAS;GAClB,OAAO,EACL,sBAAsB,MAAM;IAC1B,IAAI,CAAC,oBAAoB,KAAK,cAAc,GAC1C;IAEF,IAAI,CAAC,0BAA0B,KAAK,UAAU,GAC5C;IAEF,QAAQ,OAAO;KAAE;KAAM,WAAW;IAA2B,CAAC;GAChE,EACF;EACF;CACF,EACF;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-raw-route-query-client.cjs","names":["getPropertyName","isIdentifier","getImportedName"],"sources":["../src/no-raw-route-query-client.ts"],"sourcesContent":["import { eslintCompatPlugin } from \"@oxlint/plugins\";\nimport type { Ranged } from \"@oxlint/plugins\";\n\nimport { getImportedName, getPropertyName, isIdentifier } from \"./utils.ts\";\n\nconst RAW_QUERY_CLIENT_METHODS = new Map([\n [\"ensureQueryData\", \"ensureRouteQueryData\"],\n [\"ensureInfiniteQueryData\", \"ensureRouteInfiniteQueryData\"],\n [\"fetchQuery\", \"fetchRouteQuery\"],\n [\"prefetchQuery\", \"prefetchRouteQuery\"],\n]);\nconst RAW_QUERY_CLIENT_RECEIVERS = new Set([\"qc\", \"queryClient\"]);\nconst TANSTACK_QUERY_MODULE = \"@tanstack/react-query\";\nconst ROUTE_QUERY_HELPERS_MODULE = \"@/lib/react-query\";\nconst GENERIC_ROUTE_QUERY_HELPERS = new Map([\n [\"ensureCriticalQueryData\", \"ensureRouteQueryData\"],\n [\"prefetchNonCriticalQuery\", \"prefetchRouteQuery\"],\n]);\nconst QUERY_SUBSCRIPTION_HOOKS = new Set([\n \"useInfiniteQuery\",\n \"useQueries\",\n \"useQuery\",\n \"useSuspenseInfiniteQuery\",\n \"useSuspenseQueries\",\n \"useSuspenseQuery\",\n]);\n\nconst ROUTE_LOADER_HOOKS = new Set([\"beforeLoad\", \"loader\"]);\nconst ROUTE_PENDING_COMPONENT_HOOK = \"pendingComponent\";\n\nconst isQueryClientReceiver = (node) => {\n if (!node) {\n return false;\n }\n\n if (node.type === \"Identifier\") {\n return RAW_QUERY_CLIENT_RECEIVERS.has(node.name);\n }\n\n if (node.type !== \"MemberExpression\" || node.computed) {\n return false;\n }\n\n const receiverName = getPropertyName(node.property);\n return receiverName === \"queryClient\";\n};\n\nconst findRouteLoaderHook = (node) => {\n let current = node.parent;\n\n while (current) {\n if (current.type === \"Property\") {\n const name = getPropertyName(current.key);\n\n if (name !== null && ROUTE_LOADER_HOOKS.has(name)) {\n return name;\n }\n }\n\n current = current.parent;\n }\n\n return null;\n};\n\nconst findPendingComponentCandidate = (node) => {\n let current = node.parent;\n\n while (current) {\n if (current.type === \"Property\") {\n const name = getPropertyName(current.key);\n\n if (name === ROUTE_PENDING_COMPONENT_HOOK) {\n return ROUTE_PENDING_COMPONENT_HOOK;\n }\n }\n\n if (current.type === \"FunctionDeclaration\" && isIdentifier(current.id)) {\n return current.id.name;\n }\n\n if (current.type === \"VariableDeclarator\" && isIdentifier(current.id)) {\n return current.id.name;\n }\n\n current = current.parent;\n }\n\n return null;\n};\n\nconst getQuerySubscriptionHookName = (\n callee,\n queryHookAliases,\n tanstackQueryNamespaces,\n) => {\n if (isIdentifier(callee) && queryHookAliases.has(callee.name)) {\n return callee.name;\n }\n\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n !isIdentifier(callee.object) ||\n !tanstackQueryNamespaces.has(callee.object.name)\n ) {\n return null;\n }\n\n const hookName = getPropertyName(callee.property);\n return hookName !== null && QUERY_SUBSCRIPTION_HOOKS.has(hookName)\n ? hookName\n : null;\n};\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-raw-route-query-client\" },\n rules: {\n \"no-raw-route-query-client\": {\n meta: {\n type: \"problem\",\n messages: {\n noRawRouteQueryClient:\n \"Raw queryClient.{{method}} inside route {{hook}} \" +\n \"is forbidden. Use {{replacement}}(...), so route-seeded \" +\n \"queries carry a freshness window.\",\n noGenericRouteQueryHelper:\n \"Generic {{helper}} inside route {{hook}} is forbidden. \" +\n \"Use {{replacement}}(...), so route-seeded queries carry \" +\n \"a freshness window.\",\n noQueryHookInPendingComponent:\n \"TanStack Query subscription hook {{hook}} is forbidden \" +\n \"inside route pendingComponent {{component}}. Read cached \" +\n \"data synchronously with useQueryClient().getQueryData(...) \" +\n \"so abandoned pending renders cannot receive async state updates.\",\n },\n },\n createOnce(context) {\n const genericHelperAliases = new Map();\n const pendingComponentNames = new Set();\n const pendingQueryHookCalls: {\n component: string;\n hook: string;\n node: Ranged;\n }[] = [];\n const queryHookAliases = new Set();\n const routeQueryHelperNamespaces = new Set();\n const tanstackQueryNamespaces = new Set();\n\n return {\n before() {\n genericHelperAliases.clear();\n pendingComponentNames.clear();\n pendingQueryHookCalls.length = 0;\n queryHookAliases.clear();\n routeQueryHelperNamespaces.clear();\n tanstackQueryNamespaces.clear();\n },\n ImportDeclaration(node) {\n if (node.source?.value === TANSTACK_QUERY_MODULE) {\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportNamespaceSpecifier\") {\n tanstackQueryNamespaces.add(specifier.local.name);\n continue;\n }\n if (specifier.type !== \"ImportSpecifier\") {\n continue;\n }\n\n const importedName = getImportedName(specifier);\n if (\n importedName !== null &&\n QUERY_SUBSCRIPTION_HOOKS.has(importedName)\n ) {\n queryHookAliases.add(specifier.local.name);\n }\n }\n return;\n }\n\n if (node.source?.value !== ROUTE_QUERY_HELPERS_MODULE) {\n return;\n }\n\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportNamespaceSpecifier\") {\n routeQueryHelperNamespaces.add(specifier.local.name);\n continue;\n }\n if (specifier.type !== \"ImportSpecifier\") {\n continue;\n }\n\n const importedName = getImportedName(specifier);\n const replacement =\n importedName === null\n ? undefined\n : GENERIC_ROUTE_QUERY_HELPERS.get(importedName);\n if (replacement === undefined) {\n continue;\n }\n\n genericHelperAliases.set(specifier.local.name, {\n helper: importedName,\n replacement,\n });\n }\n },\n\n Property(node) {\n const name = getPropertyName(node.key);\n if (name !== ROUTE_PENDING_COMPONENT_HOOK) {\n return;\n }\n if (isIdentifier(node.value)) {\n pendingComponentNames.add(node.value.name);\n }\n },\n\n CallExpression(node) {\n const hook = findRouteLoaderHook(node);\n const callee = node.callee;\n\n if (hook !== null) {\n if (isIdentifier(callee)) {\n const helper = genericHelperAliases.get(callee.name);\n if (helper !== undefined) {\n context.report({\n node,\n messageId: \"noGenericRouteQueryHelper\",\n data: { hook, ...helper },\n });\n return;\n }\n }\n\n if (\n callee.type === \"MemberExpression\" &&\n callee.computed === false &&\n isIdentifier(callee.object) &&\n routeQueryHelperNamespaces.has(callee.object.name)\n ) {\n const helperName = getPropertyName(callee.property);\n const replacement =\n helperName === null\n ? undefined\n : GENERIC_ROUTE_QUERY_HELPERS.get(helperName);\n\n if (replacement !== undefined) {\n context.report({\n node,\n messageId: \"noGenericRouteQueryHelper\",\n data: { helper: helperName, hook, replacement },\n });\n return;\n }\n }\n\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n isQueryClientReceiver(callee.object)\n ) {\n const method = getPropertyName(callee.property);\n const replacement =\n method === null\n ? undefined\n : RAW_QUERY_CLIENT_METHODS.get(method);\n\n if (replacement === undefined) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noRawRouteQueryClient\",\n data: { method, hook, replacement },\n });\n return;\n }\n }\n\n const pendingComponent = findPendingComponentCandidate(node);\n if (pendingComponent === null) {\n return;\n }\n\n const queryHookName = getQuerySubscriptionHookName(\n callee,\n queryHookAliases,\n tanstackQueryNamespaces,\n );\n if (queryHookName === null) {\n return;\n }\n\n pendingQueryHookCalls.push({\n component: pendingComponent,\n hook: queryHookName,\n node,\n });\n },\n\n \"Program:exit\"() {\n for (const { component, hook, node } of pendingQueryHookCalls) {\n if (\n component !== ROUTE_PENDING_COMPONENT_HOOK &&\n !pendingComponentNames.has(component)\n ) {\n continue;\n }\n\n context.report({\n node,\n messageId: \"noQueryHookInPendingComponent\",\n data: { component, hook },\n });\n }\n },\n };\n },\n },\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"no-raw-route-query-client.cjs","names":["getPropertyName","isIdentifier","eslintCompatPlugin","getImportedName"],"sources":["../src/no-raw-route-query-client.ts"],"sourcesContent":["import { eslintCompatPlugin } from \"@oxlint/plugins\";\nimport type { Ranged } from \"@oxlint/plugins\";\n\nimport { getImportedName, getPropertyName, isIdentifier } from \"./utils.ts\";\n\nconst RAW_QUERY_CLIENT_METHODS = new Map([\n [\"ensureQueryData\", \"ensureRouteQueryData\"],\n [\"ensureInfiniteQueryData\", \"ensureRouteInfiniteQueryData\"],\n [\"fetchQuery\", \"fetchRouteQuery\"],\n [\"prefetchQuery\", \"prefetchRouteQuery\"],\n]);\nconst RAW_QUERY_CLIENT_RECEIVERS = new Set([\"qc\", \"queryClient\"]);\nconst TANSTACK_QUERY_MODULE = \"@tanstack/react-query\";\nconst ROUTE_QUERY_HELPERS_MODULE = \"@/lib/react-query\";\nconst GENERIC_ROUTE_QUERY_HELPERS = new Map([\n [\"ensureCriticalQueryData\", \"ensureRouteQueryData\"],\n [\"prefetchNonCriticalQuery\", \"prefetchRouteQuery\"],\n]);\nconst QUERY_SUBSCRIPTION_HOOKS = new Set([\n \"useInfiniteQuery\",\n \"useQueries\",\n \"useQuery\",\n \"useSuspenseInfiniteQuery\",\n \"useSuspenseQueries\",\n \"useSuspenseQuery\",\n]);\n\nconst ROUTE_LOADER_HOOKS = new Set([\"beforeLoad\", \"loader\"]);\nconst ROUTE_PENDING_COMPONENT_HOOK = \"pendingComponent\";\n\nconst isQueryClientReceiver = (node) => {\n if (!node) {\n return false;\n }\n\n if (node.type === \"Identifier\") {\n return RAW_QUERY_CLIENT_RECEIVERS.has(node.name);\n }\n\n if (node.type !== \"MemberExpression\" || node.computed) {\n return false;\n }\n\n const receiverName = getPropertyName(node.property);\n return receiverName === \"queryClient\";\n};\n\nconst findRouteLoaderHook = (node) => {\n let current = node.parent;\n\n while (current) {\n if (current.type === \"Property\") {\n const name = getPropertyName(current.key);\n\n if (name !== null && ROUTE_LOADER_HOOKS.has(name)) {\n return name;\n }\n }\n\n current = current.parent;\n }\n\n return null;\n};\n\nconst findPendingComponentCandidate = (node) => {\n let current = node.parent;\n\n while (current) {\n if (current.type === \"Property\") {\n const name = getPropertyName(current.key);\n\n if (name === ROUTE_PENDING_COMPONENT_HOOK) {\n return ROUTE_PENDING_COMPONENT_HOOK;\n }\n }\n\n if (current.type === \"FunctionDeclaration\" && isIdentifier(current.id)) {\n return current.id.name;\n }\n\n if (current.type === \"VariableDeclarator\" && isIdentifier(current.id)) {\n return current.id.name;\n }\n\n current = current.parent;\n }\n\n return null;\n};\n\nconst getQuerySubscriptionHookName = (\n callee,\n queryHookAliases,\n tanstackQueryNamespaces,\n) => {\n if (isIdentifier(callee) && queryHookAliases.has(callee.name)) {\n return callee.name;\n }\n\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n !isIdentifier(callee.object) ||\n !tanstackQueryNamespaces.has(callee.object.name)\n ) {\n return null;\n }\n\n const hookName = getPropertyName(callee.property);\n return hookName !== null && QUERY_SUBSCRIPTION_HOOKS.has(hookName)\n ? hookName\n : null;\n};\n\nexport default eslintCompatPlugin({\n meta: { name: \"no-raw-route-query-client\" },\n rules: {\n \"no-raw-route-query-client\": {\n meta: {\n type: \"problem\",\n messages: {\n noRawRouteQueryClient:\n \"Raw queryClient.{{method}} inside route {{hook}} \" +\n \"is forbidden. Use {{replacement}}(...), so route-seeded \" +\n \"queries carry a freshness window.\",\n noGenericRouteQueryHelper:\n \"Generic {{helper}} inside route {{hook}} is forbidden. \" +\n \"Use {{replacement}}(...), so route-seeded queries carry \" +\n \"a freshness window.\",\n noQueryHookInPendingComponent:\n \"TanStack Query subscription hook {{hook}} is forbidden \" +\n \"inside route pendingComponent {{component}}. Read cached \" +\n \"data synchronously with useQueryClient().getQueryData(...) \" +\n \"so abandoned pending renders cannot receive async state updates.\",\n },\n },\n createOnce(context) {\n const genericHelperAliases = new Map();\n const pendingComponentNames = new Set();\n const pendingQueryHookCalls: {\n component: string;\n hook: string;\n node: Ranged;\n }[] = [];\n const queryHookAliases = new Set();\n const routeQueryHelperNamespaces = new Set();\n const tanstackQueryNamespaces = new Set();\n\n return {\n before() {\n genericHelperAliases.clear();\n pendingComponentNames.clear();\n pendingQueryHookCalls.length = 0;\n queryHookAliases.clear();\n routeQueryHelperNamespaces.clear();\n tanstackQueryNamespaces.clear();\n },\n ImportDeclaration(node) {\n if (node.source?.value === TANSTACK_QUERY_MODULE) {\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportNamespaceSpecifier\") {\n tanstackQueryNamespaces.add(specifier.local.name);\n continue;\n }\n if (specifier.type !== \"ImportSpecifier\") {\n continue;\n }\n\n const importedName = getImportedName(specifier);\n if (\n importedName !== null &&\n QUERY_SUBSCRIPTION_HOOKS.has(importedName)\n ) {\n queryHookAliases.add(specifier.local.name);\n }\n }\n return;\n }\n\n if (node.source?.value !== ROUTE_QUERY_HELPERS_MODULE) {\n return;\n }\n\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportNamespaceSpecifier\") {\n routeQueryHelperNamespaces.add(specifier.local.name);\n continue;\n }\n if (specifier.type !== \"ImportSpecifier\") {\n continue;\n }\n\n const importedName = getImportedName(specifier);\n const replacement =\n importedName === null\n ? undefined\n : GENERIC_ROUTE_QUERY_HELPERS.get(importedName);\n if (replacement === undefined) {\n continue;\n }\n\n genericHelperAliases.set(specifier.local.name, {\n helper: importedName,\n replacement,\n });\n }\n },\n\n Property(node) {\n const name = getPropertyName(node.key);\n if (name !== ROUTE_PENDING_COMPONENT_HOOK) {\n return;\n }\n if (isIdentifier(node.value)) {\n pendingComponentNames.add(node.value.name);\n }\n },\n\n CallExpression(node) {\n const hook = findRouteLoaderHook(node);\n const callee = node.callee;\n\n if (hook !== null) {\n if (isIdentifier(callee)) {\n const helper = genericHelperAliases.get(callee.name);\n if (helper !== undefined) {\n context.report({\n node,\n messageId: \"noGenericRouteQueryHelper\",\n data: { hook, ...helper },\n });\n return;\n }\n }\n\n if (\n callee.type === \"MemberExpression\" &&\n callee.computed === false &&\n isIdentifier(callee.object) &&\n routeQueryHelperNamespaces.has(callee.object.name)\n ) {\n const helperName = getPropertyName(callee.property);\n const replacement =\n helperName === null\n ? undefined\n : GENERIC_ROUTE_QUERY_HELPERS.get(helperName);\n\n if (replacement !== undefined) {\n context.report({\n node,\n messageId: \"noGenericRouteQueryHelper\",\n data: { helper: helperName, hook, replacement },\n });\n return;\n }\n }\n\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n isQueryClientReceiver(callee.object)\n ) {\n const method = getPropertyName(callee.property);\n const replacement =\n method === null\n ? undefined\n : RAW_QUERY_CLIENT_METHODS.get(method);\n\n if (replacement === undefined) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noRawRouteQueryClient\",\n data: { method, hook, replacement },\n });\n return;\n }\n }\n\n const pendingComponent = findPendingComponentCandidate(node);\n if (pendingComponent === null) {\n return;\n }\n\n const queryHookName = getQuerySubscriptionHookName(\n callee,\n queryHookAliases,\n tanstackQueryNamespaces,\n );\n if (queryHookName === null) {\n return;\n }\n\n pendingQueryHookCalls.push({\n component: pendingComponent,\n hook: queryHookName,\n node,\n });\n },\n\n \"Program:exit\"() {\n for (const { component, hook, node } of pendingQueryHookCalls) {\n if (\n component !== ROUTE_PENDING_COMPONENT_HOOK &&\n !pendingComponentNames.has(component)\n ) {\n continue;\n }\n\n context.report({\n node,\n messageId: \"noQueryHookInPendingComponent\",\n data: { component, hook },\n });\n }\n },\n };\n },\n },\n },\n});\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as getImportedName, o as isIdentifier, r as getPropertyName } from "./utils.mjs";
|
|
2
2
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
3
3
|
//#region src/no-raw-route-query-client.ts
|
|
4
4
|
const RAW_QUERY_CLIENT_METHODS = /* @__PURE__ */ new Map([
|