corsa-oxlint 0.4.0 → 0.7.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.
Files changed (33) hide show
  1. package/README.md +19 -0
  2. package/dist/rules/await_thenable.js +2 -18
  3. package/dist/rules/await_thenable.js.map +1 -1
  4. package/dist/rules/native_bridge.d.ts +25 -0
  5. package/dist/rules/native_bridge.js +120 -0
  6. package/dist/rules/native_bridge.js.map +1 -0
  7. package/dist/rules/no_array_delete.js +2 -24
  8. package/dist/rules/no_array_delete.js.map +1 -1
  9. package/dist/rules/no_base_to_string.js +1 -1
  10. package/dist/rules/no_floating_promises.js +1 -1
  11. package/dist/rules/no_for_in_array.js +2 -11
  12. package/dist/rules/no_for_in_array.js.map +1 -1
  13. package/dist/rules/no_implied_eval.js +2 -30
  14. package/dist/rules/no_implied_eval.js.map +1 -1
  15. package/dist/rules/no_mixed_enums.js +2 -36
  16. package/dist/rules/no_mixed_enums.js.map +1 -1
  17. package/dist/rules/no_unsafe_return.js +1 -1
  18. package/dist/rules/no_unsafe_unary_minus.js +2 -23
  19. package/dist/rules/no_unsafe_unary_minus.js.map +1 -1
  20. package/dist/rules/only_throw_error.js +2 -11
  21. package/dist/rules/only_throw_error.js.map +1 -1
  22. package/dist/rules/prefer_find.js +2 -20
  23. package/dist/rules/prefer_find.js.map +1 -1
  24. package/dist/rules/prefer_includes.js +2 -16
  25. package/dist/rules/prefer_includes.js.map +1 -1
  26. package/dist/rules/prefer_promise_reject_errors.js +1 -1
  27. package/dist/rules/prefer_regexp_exec.js +2 -15
  28. package/dist/rules/prefer_regexp_exec.js.map +1 -1
  29. package/dist/rules/prefer_string_starts_ends_with.js +1 -1
  30. package/dist/rules/require_array_sort_compare.js +1 -1
  31. package/dist/rules/use_unknown_in_catch_callback_variable.js +2 -14
  32. package/dist/rules/use_unknown_in_catch_callback_variable.js.map +1 -1
  33. package/package.json +2 -2
package/README.md CHANGED
@@ -140,6 +140,25 @@ The remaining upstream rules stay listed in `pendingNativeRuleNames`, and
140
140
  `native_rules.test.ts` fails if implemented + pending drift away from the
141
141
  tracked upstream rule list.
142
142
 
143
+ ## Rust-Authored Rule Lane
144
+
145
+ General-purpose built-in rules can be implemented as Rust rules and still ship
146
+ as Oxlint JS plugin rules. The bridge is:
147
+
148
+ 1. Oxlint visits the ESTree node in JS.
149
+ 2. `corsa-oxlint` collects compact node facts and type texts.
150
+ 3. `@corsa-bind/napi` calls `corsa::lint::RustLintRule`.
151
+ 4. Rust returns Oxlint-shaped diagnostics, suggestions, and fixes.
152
+ 5. The JS rule reports them through `context.report()`.
153
+
154
+ The first rules on this path are `await-thenable`, `no-array-delete`,
155
+ `no-for-in-array`, `no-implied-eval`, `no-mixed-enums`,
156
+ `no-unsafe-unary-minus`, `only-throw-error`, `prefer-find`,
157
+ `prefer-includes`, `prefer-regexp-exec`, and
158
+ `use-unknown-in-catch-callback-variable`. Custom project-specific rules can
159
+ still be authored in JS/TS with `OxlintUtils.RuleCreator()`, while hot,
160
+ shared, tsgolint-parity rules can move into Rust incrementally.
161
+
143
162
  ## Runtime Safety Controls
144
163
 
145
164
  The underlying `@corsa-bind/napi` client now exposes a few production-oriented
@@ -1,22 +1,6 @@
1
- import { isIdentifierNamed, memberObject, memberPropertyName, stripChainExpression } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
3
- import { isPromiseLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
4
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/await_thenable.ts
5
- const awaitThenableRule = createNativeRule("await-thenable", {
6
- docs: { description: "Disallow awaiting non-thenable values." },
7
- messages: { unexpected: "Unexpected await of a non-thenable value." }
8
- }, (context) => ({ AwaitExpression(node) {
9
- if (!isPromiseLikeNode(context, node.argument) && !isObviouslyPromiseLike(node.argument)) context.report({
10
- node,
11
- messageId: "unexpected"
12
- });
13
- } }));
14
- function isObviouslyPromiseLike(node) {
15
- const current = stripChainExpression(node);
16
- if (current?.type === "NewExpression" && isIdentifierNamed(current.callee, "Promise")) return true;
17
- if (current?.type !== "CallExpression") return false;
18
- return memberPropertyName(current.callee) === "resolve" && isIdentifierNamed(memberObject(current.callee), "Promise");
19
- }
3
+ const awaitThenableRule = createRustNativeRule("await-thenable");
20
4
  //#endregion
21
5
  export { awaitThenableRule };
22
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"await_thenable.js","names":[],"sources":["../../ts/rules/await_thenable.ts"],"sourcesContent":["import { isIdentifierNamed, memberObject, memberPropertyName, stripChainExpression } from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\nimport { isPromiseLikeNode } from \"./type_utils\";\n\nexport const awaitThenableRule = createNativeRule(\n \"await-thenable\",\n {\n docs: {\n description: \"Disallow awaiting non-thenable values.\",\n },\n messages: {\n unexpected: \"Unexpected await of a non-thenable value.\",\n },\n },\n (context) => ({\n AwaitExpression(node: any) {\n if (!isPromiseLikeNode(context, node.argument) && !isObviouslyPromiseLike(node.argument)) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n\nfunction isObviouslyPromiseLike(node: any): boolean {\n const current = stripChainExpression(node);\n if (current?.type === \"NewExpression\" && isIdentifierNamed(current.callee, \"Promise\")) {\n return true;\n }\n if (current?.type !== \"CallExpression\") {\n return false;\n }\n return (\n memberPropertyName(current.callee) === \"resolve\" &&\n isIdentifierNamed(memberObject(current.callee), \"Promise\")\n );\n}\n"],"mappings":";;;;AAIA,MAAa,oBAAoB,iBAC/B,kBACA;CACE,MAAM,EACJ,aAAa,0CACd;CACD,UAAU,EACR,YAAY,6CACb;CACF,GACA,aAAa,EACZ,gBAAgB,MAAW;AACzB,KAAI,CAAC,kBAAkB,SAAS,KAAK,SAAS,IAAI,CAAC,uBAAuB,KAAK,SAAS,CACtF,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAGtD,EACF;AAED,SAAS,uBAAuB,MAAoB;CAClD,MAAM,UAAU,qBAAqB,KAAK;AAC1C,KAAI,SAAS,SAAS,mBAAmB,kBAAkB,QAAQ,QAAQ,UAAU,CACnF,QAAO;AAET,KAAI,SAAS,SAAS,iBACpB,QAAO;AAET,QACE,mBAAmB,QAAQ,OAAO,KAAK,aACvC,kBAAkB,aAAa,QAAQ,OAAO,EAAE,UAAU"}
1
+ {"version":3,"file":"await_thenable.js","names":[],"sources":["../../ts/rules/await_thenable.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const awaitThenableRule = createRustNativeRule(\"await-thenable\");\n"],"mappings":";;AAEA,MAAa,oBAAoB,qBAAqB,iBAAiB"}
@@ -0,0 +1,25 @@
1
+ import { ContextWithParserOptions } from "../types.js";
2
+ import { NativeLintDiagnostic, NativeLintNode } from "@corsa-bind/napi";
3
+
4
+ //#region src/bindings/nodejs/typescript_oxlint/ts/rules/native_bridge.d.ts
5
+ type RangedNode = {
6
+ readonly type: string;
7
+ readonly range: readonly [number, number];
8
+ };
9
+ declare function createRustNativeRule(ruleName: string): {
10
+ defaultOptions: never[];
11
+ meta: {
12
+ docs: {
13
+ requiresTypeChecking: boolean;
14
+ url: string;
15
+ };
16
+ type: "problem";
17
+ schema: never[];
18
+ };
19
+ create: (context: any) => Record<string, (node: any) => void>;
20
+ };
21
+ declare function toNativeNode(context: ContextWithParserOptions, node: RangedNode, includeTypeTexts?: boolean, maxDepth?: number): NativeLintNode;
22
+ declare function reportNativeDiagnostics(context: ContextWithParserOptions, node: RangedNode, diagnostics: readonly NativeLintDiagnostic[]): void;
23
+ //#endregion
24
+ export { createRustNativeRule, reportNativeDiagnostics, toNativeNode };
25
+ //# sourceMappingURL=native_bridge.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { createNativeRule } from "./rule_creator.js";
2
+ import { propertyNamesOfNode, typeTextsAtNode } from "./type_utils.js";
3
+ import { nativeLintRuleMetas, runNativeLintRule } from "@corsa-bind/napi";
4
+ //#region src/bindings/nodejs/typescript_oxlint/ts/rules/native_bridge.ts
5
+ const MAX_NATIVE_NODE_DEPTH = 4;
6
+ const nativeRuleMetasByName = new Map(nativeLintRuleMetas().map((meta) => [meta.name, meta]));
7
+ function createRustNativeRule(ruleName) {
8
+ const meta = nativeRuleMeta(ruleName);
9
+ return createNativeRule(ruleName, {
10
+ docs: { description: meta.docsDescription },
11
+ hasSuggestions: meta.hasSuggestions,
12
+ messages: meta.messages
13
+ }, (context) => Object.fromEntries(meta.listeners.map((listener) => [listener, (node) => {
14
+ reportNativeDiagnostics(context, node, runNativeLintRule(ruleName, toNativeNode(context, node, meta.requiresTypeTexts)));
15
+ }])));
16
+ }
17
+ function toNativeNode(context, node, includeTypeTexts = true, maxDepth = MAX_NATIVE_NODE_DEPTH) {
18
+ const fields = {};
19
+ const children = {};
20
+ const childLists = {};
21
+ for (const [key, value] of Object.entries(node)) {
22
+ if (isSkippedField(key)) continue;
23
+ if (isNativeChildNode(value)) {
24
+ if (maxDepth > 0) children[key] = toNativeNode(context, value, includeTypeTexts, maxDepth - 1);
25
+ continue;
26
+ }
27
+ if (Array.isArray(value)) {
28
+ if (maxDepth > 0 && value.every(isNativeChildNode)) childLists[key] = value.map((child) => toNativeNode(context, child, includeTypeTexts, maxDepth - 1));
29
+ else if (value.every(isJsonPrimitive)) fields[key] = value;
30
+ continue;
31
+ }
32
+ if (isPrimitiveRecord(value)) {
33
+ fields[key] = value;
34
+ continue;
35
+ }
36
+ if (isJsonPrimitive(value)) fields[key] = value;
37
+ }
38
+ const nativeNode = {
39
+ kind: node.type,
40
+ range: nativeRange(node.range)
41
+ };
42
+ if (includeTypeTexts) {
43
+ nativeNode.typeTexts = typeTextsAtNode(context, node);
44
+ nativeNode.propertyNames = propertyNamesOfNode(context, node);
45
+ }
46
+ if (Object.keys(fields).length > 0) nativeNode.fields = fields;
47
+ if (Object.keys(children).length > 0) nativeNode.children = children;
48
+ if (Object.keys(childLists).length > 0) nativeNode.childLists = childLists;
49
+ return nativeNode;
50
+ }
51
+ function reportNativeDiagnostics(context, node, diagnostics) {
52
+ for (const diagnostic of diagnostics) context.report({
53
+ node: reportNodeForRange(node, diagnostic.range),
54
+ messageId: diagnostic.messageId,
55
+ ...diagnostic.suggestions?.length ? { suggest: diagnostic.suggestions.map((suggestion) => ({
56
+ messageId: suggestion.messageId,
57
+ fix: (fixer) => suggestion.fixes.map((fix) => fixer.replaceTextRange(oxlintRange(fix.range), fix.replacementText))
58
+ })) } : {}
59
+ });
60
+ }
61
+ function reportNodeForRange(root, range) {
62
+ return findNodeByRange(root, range) ?? root;
63
+ }
64
+ function findNodeByRange(value, range, seen = /* @__PURE__ */ new Set()) {
65
+ if (typeof value !== "object" || value === null || seen.has(value)) return;
66
+ seen.add(value);
67
+ if (isNativeChildNode(value) && sameRange(value.range, range)) return value;
68
+ if (Array.isArray(value)) {
69
+ for (const item of value) {
70
+ const match = findNodeByRange(item, range, seen);
71
+ if (match) return match;
72
+ }
73
+ return;
74
+ }
75
+ for (const [key, child] of Object.entries(value)) {
76
+ if (isSkippedField(key)) continue;
77
+ const match = findNodeByRange(child, range, seen);
78
+ if (match) return match;
79
+ }
80
+ }
81
+ function nativeRuleMeta(ruleName) {
82
+ const meta = nativeRuleMetasByName.get(ruleName);
83
+ if (!meta) throw new Error(`corsa-oxlint native Rust rule is not registered: ${ruleName}`);
84
+ return meta;
85
+ }
86
+ function nativeRange(range) {
87
+ return {
88
+ start: range[0],
89
+ end: range[1]
90
+ };
91
+ }
92
+ function oxlintRange(range) {
93
+ return [range.start, range.end];
94
+ }
95
+ function sameRange(range, expected) {
96
+ return range[0] === expected.start && range[1] === expected.end;
97
+ }
98
+ function isNativeChildNode(value) {
99
+ return typeof value === "object" && value !== null && typeof value.type === "string" && isRange(value.range);
100
+ }
101
+ function isRange(value) {
102
+ return Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number";
103
+ }
104
+ function isJsonPrimitive(value) {
105
+ return value === null || [
106
+ "boolean",
107
+ "number",
108
+ "string"
109
+ ].includes(typeof value);
110
+ }
111
+ function isPrimitiveRecord(value) {
112
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every(isJsonPrimitive);
113
+ }
114
+ function isSkippedField(key) {
115
+ return key === "type" || key === "range" || key === "loc" || key === "parent";
116
+ }
117
+ //#endregion
118
+ export { createRustNativeRule, reportNativeDiagnostics, toNativeNode };
119
+
120
+ //# sourceMappingURL=native_bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native_bridge.js","names":[],"sources":["../../ts/rules/native_bridge.ts"],"sourcesContent":["import { nativeLintRuleMetas, runNativeLintRule } from \"@corsa-bind/napi\";\nimport type {\n NativeLintDiagnostic,\n NativeLintNode,\n NativeLintRange,\n NativeLintRuleMeta,\n} from \"@corsa-bind/napi\";\n\nimport { createNativeRule } from \"./rule_creator\";\nimport { propertyNamesOfNode, typeTextsAtNode } from \"./type_utils\";\nimport type { ContextWithParserOptions } from \"../types\";\n\ntype RangedNode = {\n readonly type: string;\n readonly range: readonly [number, number];\n};\n\nconst MAX_NATIVE_NODE_DEPTH = 4;\nconst nativeRuleMetasByName = new Map(nativeLintRuleMetas().map((meta) => [meta.name, meta]));\n\nexport function createRustNativeRule(ruleName: string) {\n const meta = nativeRuleMeta(ruleName);\n return createNativeRule(\n ruleName,\n {\n docs: {\n description: meta.docsDescription,\n },\n hasSuggestions: meta.hasSuggestions,\n messages: meta.messages,\n },\n (context) =>\n Object.fromEntries(\n meta.listeners.map((listener) => [\n listener,\n (node: RangedNode) => {\n reportNativeDiagnostics(\n context,\n node,\n runNativeLintRule(ruleName, toNativeNode(context, node, meta.requiresTypeTexts)),\n );\n },\n ]),\n ),\n );\n}\n\nexport function toNativeNode(\n context: ContextWithParserOptions,\n node: RangedNode,\n includeTypeTexts = true,\n maxDepth = MAX_NATIVE_NODE_DEPTH,\n): NativeLintNode {\n const fields: Record<string, unknown> = {};\n const children: Record<string, NativeLintNode> = {};\n const childLists: Record<string, NativeLintNode[]> = {};\n\n for (const [key, value] of Object.entries(node)) {\n if (isSkippedField(key)) {\n continue;\n }\n if (isNativeChildNode(value)) {\n if (maxDepth > 0) {\n children[key] = toNativeNode(context, value, includeTypeTexts, maxDepth - 1);\n }\n continue;\n }\n if (Array.isArray(value)) {\n if (maxDepth > 0 && value.every(isNativeChildNode)) {\n childLists[key] = value.map((child) =>\n toNativeNode(context, child, includeTypeTexts, maxDepth - 1),\n );\n } else if (value.every(isJsonPrimitive)) {\n fields[key] = value;\n }\n continue;\n }\n if (isPrimitiveRecord(value)) {\n fields[key] = value;\n continue;\n }\n if (isJsonPrimitive(value)) {\n fields[key] = value;\n }\n }\n\n const nativeNode: NativeLintNode = {\n kind: node.type,\n range: nativeRange(node.range),\n };\n if (includeTypeTexts) {\n nativeNode.typeTexts = typeTextsAtNode(context, node);\n nativeNode.propertyNames = propertyNamesOfNode(context, node);\n }\n if (Object.keys(fields).length > 0) {\n nativeNode.fields = fields;\n }\n if (Object.keys(children).length > 0) {\n nativeNode.children = children;\n }\n if (Object.keys(childLists).length > 0) {\n nativeNode.childLists = childLists;\n }\n return nativeNode;\n}\n\nexport function reportNativeDiagnostics(\n context: ContextWithParserOptions,\n node: RangedNode,\n diagnostics: readonly NativeLintDiagnostic[],\n): void {\n for (const diagnostic of diagnostics) {\n context.report({\n node: reportNodeForRange(node, diagnostic.range),\n messageId: diagnostic.messageId,\n ...(diagnostic.suggestions?.length\n ? {\n suggest: diagnostic.suggestions.map((suggestion) => ({\n messageId: suggestion.messageId,\n fix: (fixer: any) =>\n suggestion.fixes.map((fix) =>\n fixer.replaceTextRange(oxlintRange(fix.range), fix.replacementText),\n ),\n })),\n }\n : {}),\n } as never);\n }\n}\n\nfunction reportNodeForRange(root: RangedNode, range: NativeLintRange): RangedNode {\n return findNodeByRange(root, range) ?? root;\n}\n\nfunction findNodeByRange(\n value: unknown,\n range: NativeLintRange,\n seen = new Set<object>(),\n): RangedNode | undefined {\n if (typeof value !== \"object\" || value === null || seen.has(value)) {\n return undefined;\n }\n seen.add(value);\n\n if (isNativeChildNode(value) && sameRange(value.range, range)) {\n return value;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n const match = findNodeByRange(item, range, seen);\n if (match) {\n return match;\n }\n }\n return undefined;\n }\n\n for (const [key, child] of Object.entries(value)) {\n if (isSkippedField(key)) {\n continue;\n }\n const match = findNodeByRange(child, range, seen);\n if (match) {\n return match;\n }\n }\n return undefined;\n}\n\nfunction nativeRuleMeta(ruleName: string): NativeLintRuleMeta {\n const meta = nativeRuleMetasByName.get(ruleName);\n if (!meta) {\n throw new Error(`corsa-oxlint native Rust rule is not registered: ${ruleName}`);\n }\n return meta;\n}\n\nfunction nativeRange(range: readonly [number, number]): NativeLintRange {\n return { start: range[0], end: range[1] };\n}\n\nfunction oxlintRange(range: NativeLintRange): [number, number] {\n return [range.start, range.end];\n}\n\nfunction sameRange(range: readonly [number, number], expected: NativeLintRange): boolean {\n return range[0] === expected.start && range[1] === expected.end;\n}\n\nfunction isNativeChildNode(value: unknown): value is RangedNode {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\" &&\n isRange((value as { range?: unknown }).range)\n );\n}\n\nfunction isRange(value: unknown): value is readonly [number, number] {\n return (\n Array.isArray(value) &&\n value.length === 2 &&\n typeof value[0] === \"number\" &&\n typeof value[1] === \"number\"\n );\n}\n\nfunction isJsonPrimitive(value: unknown): value is string | number | boolean | null {\n return value === null || [\"boolean\", \"number\", \"string\"].includes(typeof value);\n}\n\nfunction isPrimitiveRecord(\n value: unknown,\n): value is Record<string, string | number | boolean | null> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.values(value).every(isJsonPrimitive)\n );\n}\n\nfunction isSkippedField(key: string): boolean {\n return key === \"type\" || key === \"range\" || key === \"loc\" || key === \"parent\";\n}\n"],"mappings":"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"}
@@ -1,28 +1,6 @@
1
- import { createNativeRule } from "./rule_creator.js";
2
- import { isArrayLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_array_delete.ts
4
- const noArrayDeleteRule = createNativeRule("no-array-delete", {
5
- docs: { description: "Disallow deleting elements from array-like values." },
6
- hasSuggestions: true,
7
- messages: {
8
- unexpected: "Do not delete elements from an array-like value.",
9
- useSplice: "Use array.splice(index, 1) instead."
10
- }
11
- }, (context) => ({ UnaryExpression(node) {
12
- if (node.operator !== "delete" || node.argument?.type !== "MemberExpression" || !node.argument.computed) return;
13
- if (isArrayLikeNode(context, node.argument.object)) context.report({
14
- node,
15
- messageId: "unexpected",
16
- suggest: [{
17
- messageId: "useSplice",
18
- fix: (fixer) => [
19
- fixer.removeRange([node.range[0], node.argument.object.range[1]]),
20
- fixer.replaceTextRange([node.argument.object.range[1], node.argument.property.range[0]], ".splice("),
21
- fixer.replaceTextRange([node.argument.property.range[1], node.argument.range[1]], ", 1)")
22
- ]
23
- }]
24
- });
25
- } }));
3
+ const noArrayDeleteRule = createRustNativeRule("no-array-delete");
26
4
  //#endregion
27
5
  export { noArrayDeleteRule };
28
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"no_array_delete.js","names":[],"sources":["../../ts/rules/no_array_delete.ts"],"sourcesContent":["import { createNativeRule } from \"./rule_creator\";\nimport { isArrayLikeNode } from \"./type_utils\";\n\nexport const noArrayDeleteRule = createNativeRule(\n \"no-array-delete\",\n {\n docs: {\n description: \"Disallow deleting elements from array-like values.\",\n },\n hasSuggestions: true,\n messages: {\n unexpected: \"Do not delete elements from an array-like value.\",\n useSplice: \"Use array.splice(index, 1) instead.\",\n },\n },\n (context) => ({\n UnaryExpression(node: any) {\n if (\n node.operator !== \"delete\" ||\n node.argument?.type !== \"MemberExpression\" ||\n !node.argument.computed\n ) {\n return;\n }\n if (isArrayLikeNode(context, node.argument.object)) {\n context.report({\n node,\n messageId: \"unexpected\",\n suggest: [\n {\n messageId: \"useSplice\",\n fix: (fixer: any) => [\n fixer.removeRange([node.range[0], node.argument.object.range[1]]),\n fixer.replaceTextRange(\n [node.argument.object.range[1], node.argument.property.range[0]],\n \".splice(\",\n ),\n fixer.replaceTextRange(\n [node.argument.property.range[1], node.argument.range[1]],\n \", 1)\",\n ),\n ],\n },\n ],\n });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,oBAAoB,iBAC/B,mBACA;CACE,MAAM,EACJ,aAAa,sDACd;CACD,gBAAgB;CAChB,UAAU;EACR,YAAY;EACZ,WAAW;EACZ;CACF,GACA,aAAa,EACZ,gBAAgB,MAAW;AACzB,KACE,KAAK,aAAa,YAClB,KAAK,UAAU,SAAS,sBACxB,CAAC,KAAK,SAAS,SAEf;AAEF,KAAI,gBAAgB,SAAS,KAAK,SAAS,OAAO,CAChD,SAAQ,OAAO;EACb;EACA,WAAW;EACX,SAAS,CACP;GACE,WAAW;GACX,MAAM,UAAe;IACnB,MAAM,YAAY,CAAC,KAAK,MAAM,IAAI,KAAK,SAAS,OAAO,MAAM,GAAG,CAAC;IACjE,MAAM,iBACJ,CAAC,KAAK,SAAS,OAAO,MAAM,IAAI,KAAK,SAAS,SAAS,MAAM,GAAG,EAChE,WACD;IACD,MAAM,iBACJ,CAAC,KAAK,SAAS,SAAS,MAAM,IAAI,KAAK,SAAS,MAAM,GAAG,EACzD,OACD;IACF;GACF,CACF;EACF,CAAC;GAGP,EACF"}
1
+ {"version":3,"file":"no_array_delete.js","names":[],"sources":["../../ts/rules/no_array_delete.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const noArrayDeleteRule = createRustNativeRule(\"no-array-delete\");\n"],"mappings":";;AAEA,MAAa,oBAAoB,qBAAqB,kBAAkB"}
@@ -1,5 +1,5 @@
1
- import { calleePropertyName, isIdentifierNamed, isLiteralString, stripChainExpression } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { calleePropertyName, isIdentifierNamed, isLiteralString, stripChainExpression } from "./ast.js";
3
3
  import { classifyTypeText, isStringLikeNode, splitTopLevelTypeText, typeTextsAtNode } from "./type_utils.js";
4
4
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_base_to_string.ts
5
5
  const knownSafeObjectTypes = new Set([
@@ -1,5 +1,5 @@
1
- import { calleePropertyName, memberObject, nearestFunctionAncestors, stripChainExpression } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { calleePropertyName, memberObject, nearestFunctionAncestors, stripChainExpression } from "./ast.js";
3
3
  import { isPromiseLikeNode } from "./type_utils.js";
4
4
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_floating_promises.ts
5
5
  const noFloatingPromisesRule = createNativeRule("no-floating-promises", {
@@ -1,15 +1,6 @@
1
- import { createNativeRule } from "./rule_creator.js";
2
- import { isArrayLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_for_in_array.ts
4
- const noForInArrayRule = createNativeRule("no-for-in-array", {
5
- docs: { description: "Disallow for-in iteration over array-like values." },
6
- messages: { unexpected: "Do not iterate over an array with a for-in loop." }
7
- }, (context) => ({ ForInStatement(node) {
8
- if (isArrayLikeNode(context, node.right)) context.report({
9
- node,
10
- messageId: "unexpected"
11
- });
12
- } }));
3
+ const noForInArrayRule = createRustNativeRule("no-for-in-array");
13
4
  //#endregion
14
5
  export { noForInArrayRule };
15
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"no_for_in_array.js","names":[],"sources":["../../ts/rules/no_for_in_array.ts"],"sourcesContent":["import { createNativeRule } from \"./rule_creator\";\nimport { isArrayLikeNode } from \"./type_utils\";\n\nexport const noForInArrayRule = createNativeRule(\n \"no-for-in-array\",\n {\n docs: {\n description: \"Disallow for-in iteration over array-like values.\",\n },\n messages: {\n unexpected: \"Do not iterate over an array with a for-in loop.\",\n },\n },\n (context) => ({\n ForInStatement(node: any) {\n if (isArrayLikeNode(context, node.right)) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,mBAAmB,iBAC9B,mBACA;CACE,MAAM,EACJ,aAAa,qDACd;CACD,UAAU,EACR,YAAY,oDACb;CACF,GACA,aAAa,EACZ,eAAe,MAAW;AACxB,KAAI,gBAAgB,SAAS,KAAK,MAAM,CACtC,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAGtD,EACF"}
1
+ {"version":3,"file":"no_for_in_array.js","names":[],"sources":["../../ts/rules/no_for_in_array.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const noForInArrayRule = createRustNativeRule(\"no-for-in-array\");\n"],"mappings":";;AAEA,MAAa,mBAAmB,qBAAqB,kBAAkB"}
@@ -1,34 +1,6 @@
1
- import { isIdentifierNamed, isLiteralString, memberPropertyName, stripChainExpression } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
3
- import { isStringLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
4
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_implied_eval.ts
5
- const impliedEvalNames = new Set([
6
- "execScript",
7
- "setInterval",
8
- "setTimeout"
9
- ]);
10
- const noImpliedEvalRule = createNativeRule("no-implied-eval", {
11
- docs: { description: "Disallow string-based dynamic code execution APIs." },
12
- messages: { unexpected: "Do not pass a string to an implied eval API." }
13
- }, (context) => ({
14
- CallExpression(node) {
15
- const callee = stripChainExpression(node.callee);
16
- const calleeName = memberPropertyName(callee) ?? (callee?.type === "Identifier" ? callee.name : void 0);
17
- if (!calleeName || !impliedEvalNames.has(calleeName)) return;
18
- const [firstArgument] = node.arguments;
19
- if (firstArgument && !firstArgument.type?.includes("Function") && (isLiteralString(firstArgument) || isStringLikeNode(context, firstArgument))) context.report({
20
- node,
21
- messageId: "unexpected"
22
- });
23
- },
24
- NewExpression(node) {
25
- if (!isIdentifierNamed(node.callee, "Function")) return;
26
- if (node.arguments.some((argument) => isLiteralString(argument))) context.report({
27
- node,
28
- messageId: "unexpected"
29
- });
30
- }
31
- }));
3
+ const noImpliedEvalRule = createRustNativeRule("no-implied-eval");
32
4
  //#endregion
33
5
  export { noImpliedEvalRule };
34
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"no_implied_eval.js","names":[],"sources":["../../ts/rules/no_implied_eval.ts"],"sourcesContent":["import {\n isIdentifierNamed,\n isLiteralString,\n memberPropertyName,\n stripChainExpression,\n} from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\nimport { isStringLikeNode } from \"./type_utils\";\n\nconst impliedEvalNames = new Set([\"execScript\", \"setInterval\", \"setTimeout\"]);\n\nexport const noImpliedEvalRule = createNativeRule(\n \"no-implied-eval\",\n {\n docs: {\n description: \"Disallow string-based dynamic code execution APIs.\",\n },\n messages: {\n unexpected: \"Do not pass a string to an implied eval API.\",\n },\n },\n (context) => ({\n CallExpression(node: any) {\n const callee = stripChainExpression(node.callee);\n const calleeName =\n memberPropertyName(callee) ?? (callee?.type === \"Identifier\" ? callee.name : undefined);\n if (!calleeName || !impliedEvalNames.has(calleeName)) {\n return;\n }\n const [firstArgument] = node.arguments;\n if (\n firstArgument &&\n !firstArgument.type?.includes(\"Function\") &&\n (isLiteralString(firstArgument) || isStringLikeNode(context, firstArgument))\n ) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n NewExpression(node: any) {\n if (!isIdentifierNamed(node.callee, \"Function\")) {\n return;\n }\n if (node.arguments.some((argument: any) => isLiteralString(argument))) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;;AASA,MAAM,mBAAmB,IAAI,IAAI;CAAC;CAAc;CAAe;CAAa,CAAC;AAE7E,MAAa,oBAAoB,iBAC/B,mBACA;CACE,MAAM,EACJ,aAAa,sDACd;CACD,UAAU,EACR,YAAY,gDACb;CACF,GACA,aAAa;CACZ,eAAe,MAAW;EACxB,MAAM,SAAS,qBAAqB,KAAK,OAAO;EAChD,MAAM,aACJ,mBAAmB,OAAO,KAAK,QAAQ,SAAS,eAAe,OAAO,OAAO,KAAA;AAC/E,MAAI,CAAC,cAAc,CAAC,iBAAiB,IAAI,WAAW,CAClD;EAEF,MAAM,CAAC,iBAAiB,KAAK;AAC7B,MACE,iBACA,CAAC,cAAc,MAAM,SAAS,WAAW,KACxC,gBAAgB,cAAc,IAAI,iBAAiB,SAAS,cAAc,EAE3E,SAAQ,OAAO;GAAE;GAAM,WAAW;GAAc,CAAC;;CAGrD,cAAc,MAAW;AACvB,MAAI,CAAC,kBAAkB,KAAK,QAAQ,WAAW,CAC7C;AAEF,MAAI,KAAK,UAAU,MAAM,aAAkB,gBAAgB,SAAS,CAAC,CACnE,SAAQ,OAAO;GAAE;GAAM,WAAW;GAAc,CAAC;;CAGtD,EACF"}
1
+ {"version":3,"file":"no_implied_eval.js","names":[],"sources":["../../ts/rules/no_implied_eval.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const noImpliedEvalRule = createRustNativeRule(\"no-implied-eval\");\n"],"mappings":";;AAEA,MAAa,oBAAoB,qBAAqB,kBAAkB"}
@@ -1,40 +1,6 @@
1
- import { createNativeRule } from "./rule_creator.js";
2
- import { isNumberLikeNode, isStringLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_mixed_enums.ts
4
- const noMixedEnumsRule = createNativeRule("no-mixed-enums", {
5
- docs: { description: "Disallow mixing string and numeric enum members." },
6
- messages: { mixed: "Mixing number and string enums can be confusing." }
7
- }, (context) => ({ TSEnumDeclaration(node) {
8
- const members = enumMembersOf(node);
9
- if (members.length === 0) return;
10
- const desiredKind = enumMemberKind(context, members[0]);
11
- if (desiredKind === "unknown") return;
12
- for (const member of members) {
13
- const currentKind = enumMemberKind(context, member);
14
- if (currentKind === "unknown") return;
15
- if (currentKind !== desiredKind) {
16
- context.report({
17
- node: member.initializer ?? member,
18
- messageId: "mixed"
19
- });
20
- return;
21
- }
22
- }
23
- } }));
24
- function enumMembersOf(node) {
25
- return node.body?.members ?? node.members ?? [];
26
- }
27
- function enumMemberKind(context, member) {
28
- const initializer = member.initializer;
29
- if (!initializer) return "number";
30
- if (initializer.type === "Literal") {
31
- if (typeof initializer.value === "number") return "number";
32
- if (typeof initializer.value === "string") return "string";
33
- }
34
- if (isStringLikeNode(context, initializer)) return "string";
35
- if (isNumberLikeNode(context, initializer)) return "number";
36
- return "unknown";
37
- }
3
+ const noMixedEnumsRule = createRustNativeRule("no-mixed-enums");
38
4
  //#endregion
39
5
  export { noMixedEnumsRule };
40
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"no_mixed_enums.js","names":[],"sources":["../../ts/rules/no_mixed_enums.ts"],"sourcesContent":["import { createNativeRule } from \"./rule_creator\";\nimport { isNumberLikeNode, isStringLikeNode } from \"./type_utils\";\n\nexport const noMixedEnumsRule = createNativeRule(\n \"no-mixed-enums\",\n {\n docs: {\n description: \"Disallow mixing string and numeric enum members.\",\n },\n messages: {\n mixed: \"Mixing number and string enums can be confusing.\",\n },\n },\n (context) => ({\n TSEnumDeclaration(node: any) {\n const members = enumMembersOf(node);\n if (members.length === 0) {\n return;\n }\n const desiredKind = enumMemberKind(context, members[0]);\n if (desiredKind === \"unknown\") {\n return;\n }\n for (const member of members) {\n const currentKind = enumMemberKind(context, member);\n if (currentKind === \"unknown\") {\n return;\n }\n if (currentKind !== desiredKind) {\n context.report({\n node: member.initializer ?? member,\n messageId: \"mixed\",\n });\n return;\n }\n }\n },\n }),\n);\n\nfunction enumMembersOf(node: any): readonly any[] {\n return node.body?.members ?? node.members ?? [];\n}\n\nfunction enumMemberKind(context: any, member: any): \"number\" | \"string\" | \"unknown\" {\n const initializer = member.initializer;\n if (!initializer) {\n return \"number\";\n }\n if (initializer.type === \"Literal\") {\n if (typeof initializer.value === \"number\") {\n return \"number\";\n }\n if (typeof initializer.value === \"string\") {\n return \"string\";\n }\n }\n if (isStringLikeNode(context, initializer)) {\n return \"string\";\n }\n if (isNumberLikeNode(context, initializer)) {\n return \"number\";\n }\n return \"unknown\";\n}\n"],"mappings":";;;AAGA,MAAa,mBAAmB,iBAC9B,kBACA;CACE,MAAM,EACJ,aAAa,oDACd;CACD,UAAU,EACR,OAAO,oDACR;CACF,GACA,aAAa,EACZ,kBAAkB,MAAW;CAC3B,MAAM,UAAU,cAAc,KAAK;AACnC,KAAI,QAAQ,WAAW,EACrB;CAEF,MAAM,cAAc,eAAe,SAAS,QAAQ,GAAG;AACvD,KAAI,gBAAgB,UAClB;AAEF,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,cAAc,eAAe,SAAS,OAAO;AACnD,MAAI,gBAAgB,UAClB;AAEF,MAAI,gBAAgB,aAAa;AAC/B,WAAQ,OAAO;IACb,MAAM,OAAO,eAAe;IAC5B,WAAW;IACZ,CAAC;AACF;;;GAIP,EACF;AAED,SAAS,cAAc,MAA2B;AAChD,QAAO,KAAK,MAAM,WAAW,KAAK,WAAW,EAAE;;AAGjD,SAAS,eAAe,SAAc,QAA8C;CAClF,MAAM,cAAc,OAAO;AAC3B,KAAI,CAAC,YACH,QAAO;AAET,KAAI,YAAY,SAAS,WAAW;AAClC,MAAI,OAAO,YAAY,UAAU,SAC/B,QAAO;AAET,MAAI,OAAO,YAAY,UAAU,SAC/B,QAAO;;AAGX,KAAI,iBAAiB,SAAS,YAAY,CACxC,QAAO;AAET,KAAI,iBAAiB,SAAS,YAAY,CACxC,QAAO;AAET,QAAO"}
1
+ {"version":3,"file":"no_mixed_enums.js","names":[],"sources":["../../ts/rules/no_mixed_enums.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const noMixedEnumsRule = createRustNativeRule(\"no-mixed-enums\");\n"],"mappings":";;AAEA,MAAa,mBAAmB,qBAAqB,iBAAiB"}
@@ -1,5 +1,5 @@
1
- import { nearestFunctionAncestors } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { nearestFunctionAncestors } from "./ast.js";
3
3
  import { checkerFor, typeAtNode, typeTextsAtNode } from "./type_utils.js";
4
4
  import { isUnsafeReturn } from "@corsa-bind/napi";
5
5
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_unsafe_return.ts
@@ -1,27 +1,6 @@
1
- import { createNativeRule } from "./rule_creator.js";
2
- import { classifyTypeText, splitTypeText, typeTextsAtNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/no_unsafe_unary_minus.ts
4
- const noUnsafeUnaryMinusRule = createNativeRule("no-unsafe-unary-minus", {
5
- docs: { description: "Disallow unary negation on non-number and non-bigint values." },
6
- messages: { unaryMinus: "Argument of unary negation should be assignable to number | bigint." }
7
- }, (context) => ({ UnaryExpression(node) {
8
- if (node.operator !== "-") return;
9
- if (isSafeLiteral(node.argument)) return;
10
- const typeTexts = typeTextsAtNode(context, node.argument);
11
- if (typeTexts.length > 0 && typeTexts.every((text) => {
12
- return splitTypeText(text).every((part) => {
13
- const kind = classifyTypeText(part);
14
- return kind === "any" || kind === "number" || kind === "bigint";
15
- });
16
- })) return;
17
- context.report({
18
- node,
19
- messageId: "unaryMinus"
20
- });
21
- } }));
22
- function isSafeLiteral(node) {
23
- return node?.type === "Literal" && (typeof node.value === "number" || typeof node.bigint === "string");
24
- }
3
+ const noUnsafeUnaryMinusRule = createRustNativeRule("no-unsafe-unary-minus");
25
4
  //#endregion
26
5
  export { noUnsafeUnaryMinusRule };
27
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"no_unsafe_unary_minus.js","names":[],"sources":["../../ts/rules/no_unsafe_unary_minus.ts"],"sourcesContent":["import { createNativeRule } from \"./rule_creator\";\nimport { classifyTypeText, splitTypeText, typeTextsAtNode } from \"./type_utils\";\n\nexport const noUnsafeUnaryMinusRule = createNativeRule(\n \"no-unsafe-unary-minus\",\n {\n docs: {\n description: \"Disallow unary negation on non-number and non-bigint values.\",\n },\n messages: {\n unaryMinus: \"Argument of unary negation should be assignable to number | bigint.\",\n },\n },\n (context) => ({\n UnaryExpression(node: any) {\n if (node.operator !== \"-\") {\n return;\n }\n if (isSafeLiteral(node.argument)) {\n return;\n }\n const typeTexts = typeTextsAtNode(context, node.argument);\n if (\n typeTexts.length > 0 &&\n typeTexts.every((text) => {\n return splitTypeText(text).every((part) => {\n const kind = classifyTypeText(part);\n return kind === \"any\" || kind === \"number\" || kind === \"bigint\";\n });\n })\n ) {\n return;\n }\n context.report({ node, messageId: \"unaryMinus\" });\n },\n }),\n);\n\nfunction isSafeLiteral(node: any): boolean {\n return (\n node?.type === \"Literal\" && (typeof node.value === \"number\" || typeof node.bigint === \"string\")\n );\n}\n"],"mappings":";;;AAGA,MAAa,yBAAyB,iBACpC,yBACA;CACE,MAAM,EACJ,aAAa,gEACd;CACD,UAAU,EACR,YAAY,uEACb;CACF,GACA,aAAa,EACZ,gBAAgB,MAAW;AACzB,KAAI,KAAK,aAAa,IACpB;AAEF,KAAI,cAAc,KAAK,SAAS,CAC9B;CAEF,MAAM,YAAY,gBAAgB,SAAS,KAAK,SAAS;AACzD,KACE,UAAU,SAAS,KACnB,UAAU,OAAO,SAAS;AACxB,SAAO,cAAc,KAAK,CAAC,OAAO,SAAS;GACzC,MAAM,OAAO,iBAAiB,KAAK;AACnC,UAAO,SAAS,SAAS,SAAS,YAAY,SAAS;IACvD;GACF,CAEF;AAEF,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAEpD,EACF;AAED,SAAS,cAAc,MAAoB;AACzC,QACE,MAAM,SAAS,cAAc,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,WAAW"}
1
+ {"version":3,"file":"no_unsafe_unary_minus.js","names":[],"sources":["../../ts/rules/no_unsafe_unary_minus.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const noUnsafeUnaryMinusRule = createRustNativeRule(\"no-unsafe-unary-minus\");\n"],"mappings":";;AAEA,MAAa,yBAAyB,qBAAqB,wBAAwB"}
@@ -1,15 +1,6 @@
1
- import { createNativeRule } from "./rule_creator.js";
2
- import { isErrorLikeNode } from "./type_utils.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/only_throw_error.ts
4
- const onlyThrowErrorRule = createNativeRule("only-throw-error", {
5
- docs: { description: "Require thrown values to be Error-like." },
6
- messages: { unexpected: "Only Error-like values should be thrown." }
7
- }, (context) => ({ ThrowStatement(node) {
8
- if (node.argument && !isErrorLikeNode(context, node.argument)) context.report({
9
- node,
10
- messageId: "unexpected"
11
- });
12
- } }));
3
+ const onlyThrowErrorRule = createRustNativeRule("only-throw-error");
13
4
  //#endregion
14
5
  export { onlyThrowErrorRule };
15
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"only_throw_error.js","names":[],"sources":["../../ts/rules/only_throw_error.ts"],"sourcesContent":["import { createNativeRule } from \"./rule_creator\";\nimport { isErrorLikeNode } from \"./type_utils\";\n\nexport const onlyThrowErrorRule = createNativeRule(\n \"only-throw-error\",\n {\n docs: {\n description: \"Require thrown values to be Error-like.\",\n },\n messages: {\n unexpected: \"Only Error-like values should be thrown.\",\n },\n },\n (context) => ({\n ThrowStatement(node: any) {\n if (node.argument && !isErrorLikeNode(context, node.argument)) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,qBAAqB,iBAChC,oBACA;CACE,MAAM,EACJ,aAAa,2CACd;CACD,UAAU,EACR,YAAY,4CACb;CACF,GACA,aAAa,EACZ,eAAe,MAAW;AACxB,KAAI,KAAK,YAAY,CAAC,gBAAgB,SAAS,KAAK,SAAS,CAC3D,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAGtD,EACF"}
1
+ {"version":3,"file":"only_throw_error.js","names":[],"sources":["../../ts/rules/only_throw_error.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const onlyThrowErrorRule = createRustNativeRule(\"only-throw-error\");\n"],"mappings":";;AAEA,MAAa,qBAAqB,qBAAqB,mBAAmB"}
@@ -1,24 +1,6 @@
1
- import { calleePropertyName, memberObject, memberPropertyName } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/prefer_find.ts
4
- const preferFindRule = createNativeRule("prefer-find", {
5
- docs: { description: "Prefer find over filtering and taking the first element." },
6
- messages: { unexpected: "Use .find() instead of filtering and taking the first match." }
7
- }, (context) => ({
8
- MemberExpression(node) {
9
- if (memberPropertyName(node) === "0" && calleePropertyName(node.object) === "filter") context.report({
10
- node,
11
- messageId: "unexpected"
12
- });
13
- },
14
- CallExpression(node) {
15
- if (calleePropertyName(node) !== "at" || node.arguments[0]?.value !== 0) return;
16
- if (calleePropertyName(memberObject(node.callee)) === "filter") context.report({
17
- node,
18
- messageId: "unexpected"
19
- });
20
- }
21
- }));
3
+ const preferFindRule = createRustNativeRule("prefer-find");
22
4
  //#endregion
23
5
  export { preferFindRule };
24
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"prefer_find.js","names":[],"sources":["../../ts/rules/prefer_find.ts"],"sourcesContent":["import { calleePropertyName, memberObject, memberPropertyName } from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\n\nexport const preferFindRule = createNativeRule(\n \"prefer-find\",\n {\n docs: {\n description: \"Prefer find over filtering and taking the first element.\",\n },\n messages: {\n unexpected: \"Use .find() instead of filtering and taking the first match.\",\n },\n },\n (context) => ({\n MemberExpression(node: any) {\n if (memberPropertyName(node) === \"0\" && calleePropertyName(node.object) === \"filter\") {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n CallExpression(node: any) {\n if (calleePropertyName(node) !== \"at\" || node.arguments[0]?.value !== 0) {\n return;\n }\n if (calleePropertyName(memberObject(node.callee)) === \"filter\") {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,iBAAiB,iBAC5B,eACA;CACE,MAAM,EACJ,aAAa,4DACd;CACD,UAAU,EACR,YAAY,gEACb;CACF,GACA,aAAa;CACZ,iBAAiB,MAAW;AAC1B,MAAI,mBAAmB,KAAK,KAAK,OAAO,mBAAmB,KAAK,OAAO,KAAK,SAC1E,SAAQ,OAAO;GAAE;GAAM,WAAW;GAAc,CAAC;;CAGrD,eAAe,MAAW;AACxB,MAAI,mBAAmB,KAAK,KAAK,QAAQ,KAAK,UAAU,IAAI,UAAU,EACpE;AAEF,MAAI,mBAAmB,aAAa,KAAK,OAAO,CAAC,KAAK,SACpD,SAAQ,OAAO;GAAE;GAAM,WAAW;GAAc,CAAC;;CAGtD,EACF"}
1
+ {"version":3,"file":"prefer_find.js","names":[],"sources":["../../ts/rules/prefer_find.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const preferFindRule = createRustNativeRule(\"prefer-find\");\n"],"mappings":";;AAEA,MAAa,iBAAiB,qBAAqB,cAAc"}
@@ -1,20 +1,6 @@
1
- import { calleePropertyName, isNegativeOneLiteral, isZeroLiteral } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/prefer_includes.ts
4
- const preferIncludesRule = createNativeRule("prefer-includes", {
5
- docs: { description: "Prefer includes over indexOf/lastIndexOf comparisons." },
6
- messages: { unexpected: "Use .includes() instead of comparing an index result." }
7
- }, (context) => ({ BinaryExpression(node) {
8
- if (!isComparableIndexSearch(node.left) && !isComparableIndexSearch(node.right)) return;
9
- if (isNegativeOneLiteral(node.left) || isNegativeOneLiteral(node.right) || isZeroLiteral(node.left) || isZeroLiteral(node.right)) context.report({
10
- node,
11
- messageId: "unexpected"
12
- });
13
- } }));
14
- function isComparableIndexSearch(node) {
15
- const propertyName = calleePropertyName(node);
16
- return propertyName === "indexOf" || propertyName === "lastIndexOf";
17
- }
3
+ const preferIncludesRule = createRustNativeRule("prefer-includes");
18
4
  //#endregion
19
5
  export { preferIncludesRule };
20
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"prefer_includes.js","names":[],"sources":["../../ts/rules/prefer_includes.ts"],"sourcesContent":["import { calleePropertyName, isNegativeOneLiteral, isZeroLiteral } from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\n\nexport const preferIncludesRule = createNativeRule(\n \"prefer-includes\",\n {\n docs: {\n description: \"Prefer includes over indexOf/lastIndexOf comparisons.\",\n },\n messages: {\n unexpected: \"Use .includes() instead of comparing an index result.\",\n },\n },\n (context) => ({\n BinaryExpression(node: any) {\n if (!isComparableIndexSearch(node.left) && !isComparableIndexSearch(node.right)) {\n return;\n }\n if (\n isNegativeOneLiteral(node.left) ||\n isNegativeOneLiteral(node.right) ||\n isZeroLiteral(node.left) ||\n isZeroLiteral(node.right)\n ) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n\nfunction isComparableIndexSearch(node: any): boolean {\n const propertyName = calleePropertyName(node);\n return propertyName === \"indexOf\" || propertyName === \"lastIndexOf\";\n}\n"],"mappings":";;;AAGA,MAAa,qBAAqB,iBAChC,mBACA;CACE,MAAM,EACJ,aAAa,yDACd;CACD,UAAU,EACR,YAAY,yDACb;CACF,GACA,aAAa,EACZ,iBAAiB,MAAW;AAC1B,KAAI,CAAC,wBAAwB,KAAK,KAAK,IAAI,CAAC,wBAAwB,KAAK,MAAM,CAC7E;AAEF,KACE,qBAAqB,KAAK,KAAK,IAC/B,qBAAqB,KAAK,MAAM,IAChC,cAAc,KAAK,KAAK,IACxB,cAAc,KAAK,MAAM,CAEzB,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAGtD,EACF;AAED,SAAS,wBAAwB,MAAoB;CACnD,MAAM,eAAe,mBAAmB,KAAK;AAC7C,QAAO,iBAAiB,aAAa,iBAAiB"}
1
+ {"version":3,"file":"prefer_includes.js","names":[],"sources":["../../ts/rules/prefer_includes.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const preferIncludesRule = createRustNativeRule(\"prefer-includes\");\n"],"mappings":";;AAEA,MAAa,qBAAqB,qBAAqB,kBAAkB"}
@@ -1,5 +1,5 @@
1
- import { isIdentifierNamed, memberObject, memberPropertyName, nearestFunctionAncestors, stripChainExpression } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { isIdentifierNamed, memberObject, memberPropertyName, nearestFunctionAncestors, stripChainExpression } from "./ast.js";
3
3
  import { isAnyLikeNode, isErrorLikeNode, isPromiseLikeNode, isUnknownLikeNode } from "./type_utils.js";
4
4
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/prefer_promise_reject_errors.ts
5
5
  const defaults = {
@@ -1,19 +1,6 @@
1
- import { calleePropertyName, regexFlags } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/prefer_regexp_exec.ts
4
- const preferRegexpExecRule = createNativeRule("prefer-regexp-exec", {
5
- docs: { description: "Prefer RegExp#exec over String#match for single matches." },
6
- messages: { unexpected: "Use a RegExp exec() call instead of String match()." }
7
- }, (context) => ({ CallExpression(node) {
8
- if (calleePropertyName(node) !== "match") return;
9
- const [firstArgument] = node.arguments;
10
- if (!firstArgument) return;
11
- const flags = regexFlags(firstArgument);
12
- if (flags !== void 0 && !flags.includes("g")) context.report({
13
- node,
14
- messageId: "unexpected"
15
- });
16
- } }));
3
+ const preferRegexpExecRule = createRustNativeRule("prefer-regexp-exec");
17
4
  //#endregion
18
5
  export { preferRegexpExecRule };
19
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"prefer_regexp_exec.js","names":[],"sources":["../../ts/rules/prefer_regexp_exec.ts"],"sourcesContent":["import { calleePropertyName, regexFlags } from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\n\nexport const preferRegexpExecRule = createNativeRule(\n \"prefer-regexp-exec\",\n {\n docs: {\n description: \"Prefer RegExp#exec over String#match for single matches.\",\n },\n messages: {\n unexpected: \"Use a RegExp exec() call instead of String match().\",\n },\n },\n (context) => ({\n CallExpression(node: any) {\n if (calleePropertyName(node) !== \"match\") {\n return;\n }\n const [firstArgument] = node.arguments;\n if (!firstArgument) {\n return;\n }\n const flags = regexFlags(firstArgument);\n if (flags !== undefined && !flags.includes(\"g\")) {\n context.report({ node, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,uBAAuB,iBAClC,sBACA;CACE,MAAM,EACJ,aAAa,4DACd;CACD,UAAU,EACR,YAAY,uDACb;CACF,GACA,aAAa,EACZ,eAAe,MAAW;AACxB,KAAI,mBAAmB,KAAK,KAAK,QAC/B;CAEF,MAAM,CAAC,iBAAiB,KAAK;AAC7B,KAAI,CAAC,cACH;CAEF,MAAM,QAAQ,WAAW,cAAc;AACvC,KAAI,UAAU,KAAA,KAAa,CAAC,MAAM,SAAS,IAAI,CAC7C,SAAQ,OAAO;EAAE;EAAM,WAAW;EAAc,CAAC;GAGtD,EACF"}
1
+ {"version":3,"file":"prefer_regexp_exec.js","names":[],"sources":["../../ts/rules/prefer_regexp_exec.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const preferRegexpExecRule = createRustNativeRule(\"prefer-regexp-exec\");\n"],"mappings":";;AAEA,MAAa,uBAAuB,qBAAqB,qBAAqB"}
@@ -1,5 +1,5 @@
1
- import { calleePropertyName, isZeroLiteral, memberObject, memberPropertyName, stripChainExpression } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { calleePropertyName, isZeroLiteral, memberObject, memberPropertyName, stripChainExpression } from "./ast.js";
3
3
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/prefer_string_starts_ends_with.ts
4
4
  const comparableOperators = new Set([
5
5
  "==",
@@ -1,5 +1,5 @@
1
- import { memberObject, memberPropertyName } from "./ast.js";
2
1
  import { createNativeRule } from "./rule_creator.js";
2
+ import { memberObject, memberPropertyName } from "./ast.js";
3
3
  import { isArrayLikeNode, typeTextsAtNode } from "./type_utils.js";
4
4
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/require_array_sort_compare.ts
5
5
  const defaults = { ignoreStringArrays: true };
@@ -1,18 +1,6 @@
1
- import { calleePropertyName, hasUnknownTypeAnnotation } from "./ast.js";
2
- import { createNativeRule } from "./rule_creator.js";
1
+ import { createRustNativeRule } from "./native_bridge.js";
3
2
  //#region src/bindings/nodejs/typescript_oxlint/ts/rules/use_unknown_in_catch_callback_variable.ts
4
- const useUnknownInCatchCallbackVariableRule = createNativeRule("use-unknown-in-catch-callback-variable", {
5
- docs: { description: "Require Promise catch callback variables to use an explicit unknown annotation." },
6
- messages: { unexpected: "Catch callback variables should be explicitly typed as unknown." }
7
- }, (context) => ({ CallExpression(node) {
8
- const propertyName = calleePropertyName(node);
9
- const callback = propertyName === "catch" ? node.arguments[0] : propertyName === "then" ? node.arguments[1] : void 0;
10
- const parameter = callback?.params?.[0];
11
- if (callback?.type?.includes("Function") && parameter && !hasUnknownTypeAnnotation(parameter)) context.report({
12
- node: parameter,
13
- messageId: "unexpected"
14
- });
15
- } }));
3
+ const useUnknownInCatchCallbackVariableRule = createRustNativeRule("use-unknown-in-catch-callback-variable");
16
4
  //#endregion
17
5
  export { useUnknownInCatchCallbackVariableRule };
18
6
 
@@ -1 +1 @@
1
- {"version":3,"file":"use_unknown_in_catch_callback_variable.js","names":[],"sources":["../../ts/rules/use_unknown_in_catch_callback_variable.ts"],"sourcesContent":["import { calleePropertyName, hasUnknownTypeAnnotation } from \"./ast\";\nimport { createNativeRule } from \"./rule_creator\";\n\nexport const useUnknownInCatchCallbackVariableRule = createNativeRule(\n \"use-unknown-in-catch-callback-variable\",\n {\n docs: {\n description:\n \"Require Promise catch callback variables to use an explicit unknown annotation.\",\n },\n messages: {\n unexpected: \"Catch callback variables should be explicitly typed as unknown.\",\n },\n },\n (context) => ({\n CallExpression(node: any) {\n const propertyName = calleePropertyName(node);\n const callback =\n propertyName === \"catch\"\n ? node.arguments[0]\n : propertyName === \"then\"\n ? node.arguments[1]\n : undefined;\n const parameter = callback?.params?.[0];\n if (\n callback?.type?.includes(\"Function\") &&\n parameter &&\n !hasUnknownTypeAnnotation(parameter)\n ) {\n context.report({ node: parameter, messageId: \"unexpected\" });\n }\n },\n }),\n);\n"],"mappings":";;;AAGA,MAAa,wCAAwC,iBACnD,0CACA;CACE,MAAM,EACJ,aACE,mFACH;CACD,UAAU,EACR,YAAY,mEACb;CACF,GACA,aAAa,EACZ,eAAe,MAAW;CACxB,MAAM,eAAe,mBAAmB,KAAK;CAC7C,MAAM,WACJ,iBAAiB,UACb,KAAK,UAAU,KACf,iBAAiB,SACf,KAAK,UAAU,KACf,KAAA;CACR,MAAM,YAAY,UAAU,SAAS;AACrC,KACE,UAAU,MAAM,SAAS,WAAW,IACpC,aACA,CAAC,yBAAyB,UAAU,CAEpC,SAAQ,OAAO;EAAE,MAAM;EAAW,WAAW;EAAc,CAAC;GAGjE,EACF"}
1
+ {"version":3,"file":"use_unknown_in_catch_callback_variable.js","names":[],"sources":["../../ts/rules/use_unknown_in_catch_callback_variable.ts"],"sourcesContent":["import { createRustNativeRule } from \"./native_bridge\";\n\nexport const useUnknownInCatchCallbackVariableRule = createRustNativeRule(\n \"use-unknown-in-catch-callback-variable\",\n);\n"],"mappings":";;AAEA,MAAa,wCAAwC,qBACnD,yCACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsa-oxlint",
3
- "version": "0.4.0",
3
+ "version": "0.7.0",
4
4
  "description": "Type-aware Oxlint helpers powered by corsa and typescript-go",
5
5
  "homepage": "https://github.com/ubugeeei/corsa-bind/tree/main/src/bindings/nodejs/typescript_oxlint",
6
6
  "bugs": {
@@ -61,7 +61,7 @@
61
61
  "dependencies": {
62
62
  "@oxlint/plugins": "1.57.0",
63
63
  "oxlint": "1.57.0",
64
- "@corsa-bind/napi": "0.4.0"
64
+ "@corsa-bind/napi": "0.7.0"
65
65
  },
66
66
  "engines": {
67
67
  "node": ">=22"