@timmo001/oxlint-rules 0.6.0 → 0.6.2

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/README.md CHANGED
@@ -137,8 +137,9 @@ they only run when the consumer enables `typeAware`.
137
137
 
138
138
  - `no-raw-gh`: reports the raw `execute`, `json` and `stream` methods called on
139
139
  a `yield* Gh` binding from `@timmo001/effect-gh`, `Api.raw` from that package,
140
- and any call whose first argument is `"gh"` or an array starting with `"gh"`,
141
- such as `executor.run("gh", ...)` or `Bun.spawn(["gh", ...])`. Use the
140
+ and calls that launch gh: `"gh"` followed by its arguments, such as
141
+ `executor.run("gh", ...)`, or an argument array starting with `"gh"` passed
142
+ to a spawn, exec, run or command function, such as `Bun.spawn(["gh", ...])`. Use the
142
143
  package's typed operations, and add one to effect-gh when a command has none.
143
144
  effect-gh's own relative imports are not reported.
144
145
  - `no-try-catch-in-effect-generators`: diagnoses synchronous `try/catch` owned
package/dist/cli.js CHANGED
@@ -3004,13 +3004,20 @@ function isYieldGh(sourceCode, node) {
3004
3004
  function isGhBinding(sourceCode, identifier) {
3005
3005
  return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
3006
3006
  }
3007
- function isGhArgument(node) {
3008
- if (node?.type === "Literal")
3009
- return node.value === "gh";
3010
- if (node?.type !== "ArrayExpression")
3007
+ var launcherName = /spawn|exec|run|command/i;
3008
+ function calleeName(callee) {
3009
+ if (callee.type === "Identifier")
3010
+ return callee.name;
3011
+ return staticMemberName(callee);
3012
+ }
3013
+ function launchesGh(node) {
3014
+ const [command, argv] = node.arguments;
3015
+ if (command?.type === "Literal")
3016
+ return command.value === "gh" && argv !== undefined;
3017
+ if (command?.type !== "ArrayExpression")
3011
3018
  return false;
3012
- const first = node.elements[0];
3013
- return first?.type === "Literal" && first.value === "gh";
3019
+ const first = command.elements[0];
3020
+ return first?.type === "Literal" && first.value === "gh" && launcherName.test(calleeName(node.callee) ?? "");
3014
3021
  }
3015
3022
  var noRawGhRule = defineRule24({
3016
3023
  meta: {
@@ -3040,7 +3047,7 @@ var noRawGhRule = defineRule24({
3040
3047
  return;
3041
3048
  }
3042
3049
  }
3043
- if (isGhArgument(node.arguments[0]))
3050
+ if (launchesGh(node))
3044
3051
  context.report({ node, messageId: "spawnGh" });
3045
3052
  }
3046
3053
  };
@@ -55,13 +55,20 @@ function isYieldGh(sourceCode, node) {
55
55
  function isGhBinding(sourceCode, identifier) {
56
56
  return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
57
57
  }
58
- function isGhArgument(node) {
59
- if (node?.type === "Literal")
60
- return node.value === "gh";
61
- if (node?.type !== "ArrayExpression")
58
+ var launcherName = /spawn|exec|run|command/i;
59
+ function calleeName(callee) {
60
+ if (callee.type === "Identifier")
61
+ return callee.name;
62
+ return staticMemberName(callee);
63
+ }
64
+ function launchesGh(node) {
65
+ const [command, argv] = node.arguments;
66
+ if (command?.type === "Literal")
67
+ return command.value === "gh" && argv !== undefined;
68
+ if (command?.type !== "ArrayExpression")
62
69
  return false;
63
- const first = node.elements[0];
64
- return first?.type === "Literal" && first.value === "gh";
70
+ const first = command.elements[0];
71
+ return first?.type === "Literal" && first.value === "gh" && launcherName.test(calleeName(node.callee) ?? "");
65
72
  }
66
73
  var noRawGhRule = defineRule({
67
74
  meta: {
@@ -91,7 +98,7 @@ var noRawGhRule = defineRule({
91
98
  return;
92
99
  }
93
100
  }
94
- if (isGhArgument(node.arguments[0]))
101
+ if (launchesGh(node))
95
102
  context.report({ node, messageId: "spawnGh" });
96
103
  }
97
104
  };
@@ -50,13 +50,20 @@ function isYieldGh(sourceCode, node) {
50
50
  function isGhBinding(sourceCode, identifier) {
51
51
  return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
52
52
  }
53
- function isGhArgument(node) {
54
- if (node?.type === "Literal")
55
- return node.value === "gh";
56
- if (node?.type !== "ArrayExpression")
53
+ var launcherName = /spawn|exec|run|command/i;
54
+ function calleeName(callee) {
55
+ if (callee.type === "Identifier")
56
+ return callee.name;
57
+ return staticMemberName(callee);
58
+ }
59
+ function launchesGh(node) {
60
+ const [command, argv] = node.arguments;
61
+ if (command?.type === "Literal")
62
+ return command.value === "gh" && argv !== undefined;
63
+ if (command?.type !== "ArrayExpression")
57
64
  return false;
58
- const first = node.elements[0];
59
- return first?.type === "Literal" && first.value === "gh";
65
+ const first = command.elements[0];
66
+ return first?.type === "Literal" && first.value === "gh" && launcherName.test(calleeName(node.callee) ?? "");
60
67
  }
61
68
  var noRawGhRule = defineRule({
62
69
  meta: {
@@ -86,7 +93,7 @@ var noRawGhRule = defineRule({
86
93
  return;
87
94
  }
88
95
  }
89
- if (isGhArgument(node.arguments[0]))
96
+ if (launchesGh(node))
90
97
  context.report({ node, messageId: "spawnGh" });
91
98
  }
92
99
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmo001/oxlint-rules",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Shared Oxlint plugins and configs with optional Effect rules.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -61,13 +61,35 @@ function isGhBinding(
61
61
  );
62
62
  }
63
63
 
64
- function isGhArgument(node: ESTree.Node | undefined): boolean {
65
- if (node?.type === "Literal") return node.value === "gh";
64
+ /** Callee names that take an argv array to launch, such as `Bun.spawn` or `execFileSync`. */
65
+ const launcherName = /spawn|exec|run|command/i;
66
66
 
67
- if (node?.type !== "ArrayExpression") return false;
68
- const first = node.elements[0];
67
+ function calleeName(callee: ESTree.Expression): string | null {
68
+ if (callee.type === "Identifier") return callee.name;
69
69
 
70
- return first?.type === "Literal" && first.value === "gh";
70
+ return staticMemberName(callee);
71
+ }
72
+
73
+ /**
74
+ * Whether a call launches gh: `"gh"` followed by its argv, as in
75
+ * `run("gh", args)`, or an argv array starting with `"gh"` passed to a
76
+ * spawn, exec, run or command function. Recording argv, as in
77
+ * `calls.push(["gh", ...args])`, is not launching it.
78
+ */
79
+ function launchesGh(node: ESTree.CallExpression): boolean {
80
+ const [command, argv] = node.arguments;
81
+
82
+ if (command?.type === "Literal")
83
+ return command.value === "gh" && argv !== undefined;
84
+
85
+ if (command?.type !== "ArrayExpression") return false;
86
+ const first = command.elements[0];
87
+
88
+ return (
89
+ first?.type === "Literal" &&
90
+ first.value === "gh" &&
91
+ launcherName.test(calleeName(node.callee) ?? "")
92
+ );
71
93
  }
72
94
 
73
95
  /** Route gh through effect-gh's typed operations instead of raw argv or direct spawns. */
@@ -118,8 +140,7 @@ export const noRawGhRule = defineRule({
118
140
  }
119
141
  }
120
142
 
121
- if (isGhArgument(node.arguments[0]))
122
- context.report({ node, messageId: "spawnGh" });
143
+ if (launchesGh(node)) context.report({ node, messageId: "spawnGh" });
123
144
  },
124
145
  };
125
146
  },