Skip to content

Commit 03f83c8

Browse files
committed
test(coverage): spawn-sfw.mts to 100% (was 11.76%)
Adds 6 tests for the bespoke spawnSfwDlx flow: - local-binary path uses the resolved local sfw - local script path runs through node - 'dlx' resolution type falls back to spawnDlx - unexpected resolution type throws an internal error - custom stdio in spawnExtra is honored - empty args skip applyMachineModeIfActive Vfs and auto-dispatch are tested via the shared define-tool-spawn factory tests.
1 parent 0703087 commit 03f83c8

187 files changed

Lines changed: 1029 additions & 912 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/oxlint-plugin/rules/no-fetch-prefer-http-request.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const rule = {
4141

4242
// Skip if `fetch` is locally shadowed by a parameter / declaration.
4343
// Best-effort: check the scope chain.
44-
const scope = context.getScope ? context.getScope() : null
44+
const scope = context.getScope ? context.getScope() : undefined
4545
if (scope) {
4646
const variable = scope.references.find(
4747
ref => ref.identifier === callee,

.config/oxlint-plugin/rules/no-promise-race-in-loop.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,9 @@
2020
* Reporting only.
2121
*/
2222

23-
const RACE_METHODS = new Set(['race', 'any'])
23+
const RACE_METHODS = new Set(['any', 'race'])
2424

25-
const LOOP_TYPES = new Set([
26-
'ForStatement',
27-
'ForOfStatement',
28-
'ForInStatement',
29-
'WhileStatement',
30-
'DoWhileStatement',
31-
])
25+
const LOOP_TYPES = new Set(['DoWhileStatement', 'ForInStatement', 'ForOfStatement', 'ForStatement', 'WhileStatement'])
3226

3327
function isInsideLoop(node) {
3428
let current = node.parent

.config/oxlint-plugin/rules/no-status-emoji.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const rule = {
6060
return emoji
6161
}
6262
}
63-
return null
63+
return undefined
6464
}
6565

6666
/**
@@ -71,7 +71,7 @@ const rule = {
7171
function leadingEmoji(value) {
7272
const match = EMOJI_LEAD_RE.exec(value)
7373
if (!match) {
74-
return null
74+
return undefined
7575
}
7676
return {
7777
emoji: match[1],
@@ -86,30 +86,30 @@ const rule = {
8686
function tryFix(node, literalNode, leadInfo) {
8787
const method = EMOJI_TO_METHOD[leadInfo.emoji]
8888
if (!method) {
89-
return null
89+
return undefined
9090
}
9191

9292
// Only fix when the parent is a CallExpression and the literal
9393
// is the first argument. Otherwise leave to the human.
9494
const parent = node.parent
9595
if (!parent || parent.type !== 'CallExpression') {
96-
return null
96+
return undefined
9797
}
9898
if (parent.arguments[0] !== literalNode) {
99-
return null
99+
return undefined
100100
}
101101

102102
const callee = parent.callee
103103
if (callee.type !== 'MemberExpression') {
104-
return null
104+
return undefined
105105
}
106106

107107
const objectName =
108-
callee.object.type === 'Identifier' ? callee.object.name : null
108+
callee.object.type === 'Identifier' ? callee.object.name : undefined
109109
const propName =
110-
callee.property.type === 'Identifier' ? callee.property.name : null
110+
callee.property.type === 'Identifier' ? callee.property.name : undefined
111111
if (!objectName || !propName) {
112-
return null
112+
return undefined
113113
}
114114

115115
const isConsole =
@@ -119,7 +119,7 @@ const rule = {
119119
objectName === 'logger' && (propName === 'log' || propName === 'info')
120120

121121
if (!isConsole && !isLoggerLog) {
122-
return null
122+
return undefined
123123
}
124124

125125
// Build the replacement.
@@ -133,7 +133,7 @@ const rule = {
133133
}
134134

135135
function reportLiteral(node) {
136-
const value = typeof node.value === 'string' ? node.value : null
136+
const value = typeof node.value === 'string' ? node.value : undefined
137137
if (!value) {
138138
return
139139
}
@@ -144,7 +144,7 @@ const rule = {
144144
}
145145

146146
const leadInfo = leadingEmoji(value)
147-
const method = leadInfo ? EMOJI_TO_METHOD[leadInfo.emoji] : null
147+
const method = leadInfo ? EMOJI_TO_METHOD[leadInfo.emoji] : undefined
148148

149149
if (leadInfo && method) {
150150
const fix = tryFix(node, node, leadInfo)

.config/oxlint-plugin/rules/prefer-exists-sync.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020

2121
const ACCESS_METHODS = new Set(['access', 'accessSync'])
22-
const STAT_METHODS = new Set(['stat', 'statSync', 'lstat', 'lstatSync'])
22+
const STAT_METHODS = new Set(['lstat', 'lstatSync', 'stat', 'statSync'])
2323

2424
/** @type {import('eslint').Rule.RuleModule} */
2525
const rule = {
@@ -44,10 +44,10 @@ const rule = {
4444
create(context) {
4545
function calleeMethodName(callee) {
4646
if (callee.type !== 'MemberExpression') {
47-
return null
47+
return undefined
4848
}
4949
if (callee.property.type !== 'Identifier') {
50-
return null
50+
return undefined
5151
}
5252
return callee.property.name
5353
}

.config/oxlint-plugin/rules/prefer-safe-delete.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@
1717
* (`.claude/hooks/path-guard/`) — this rule covers the JavaScript side.
1818
*/
1919

20-
const DELETE_METHODS = new Set([
21-
'rm',
22-
'rmSync',
23-
'unlink',
24-
'unlinkSync',
25-
'rmdir',
26-
'rmdirSync',
27-
])
20+
const DELETE_METHODS = new Set(['rm', 'rmSync', 'rmdir', 'rmdirSync', 'unlink', 'unlinkSync'])
2821

2922
/** @type {import('eslint').Rule.RuleModule} */
3023
const rule = {
@@ -69,7 +62,7 @@ const rule = {
6962
: obj.type === 'MemberExpression' &&
7063
obj.property.type === 'Identifier'
7164
? obj.property.name
72-
: null
65+
: undefined
7366

7467
if (!objName) {
7568
return

.config/oxlint-plugin/rules/sort-set-args.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* but not auto-fixed (sorting computed values would change behavior).
1111
*/
1212

13-
const SET_NAMES = new Set(['Set', 'SafeSet'])
13+
const SET_NAMES = new Set(['SafeSet', 'Set'])
1414

1515
function isSortableElement(node) {
1616
return (

.config/oxlint-plugin/rules/sort-source-methods.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function declVisibility(node) {
4141
if (node.type === 'FunctionDeclaration') {
4242
return { visibility: 'private', fn: node }
4343
}
44-
return null
44+
return undefined
4545
}
4646

4747
/** @type {import('eslint').Rule.RuleModule} */
@@ -67,8 +67,8 @@ const rule = {
6767
return {
6868
Program(programNode) {
6969
let lastVisibilityRank = -1
70-
let lastNameInGroup = null
71-
let currentVisibility = null
70+
let lastNameInGroup = undefined
71+
let currentVisibility = undefined
7272

7373
for (const node of programNode.body) {
7474
const info = declVisibility(node)

.git-hooks/pre-push.mts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ const computeRange = (
100100
): string | null => {
101101
if (localRef.startsWith('refs/tags/')) {
102102
logger.info(`Skipping tag push: ${localRef}`)
103-
return null
103+
return undefined
104104
}
105105
if (localSha === ZERO_SHA) {
106-
return null
106+
return undefined
107107
}
108108

109109
const defaultBranchOf = (remoteName: string): string => {
@@ -132,7 +132,7 @@ const computeRange = (
132132
const baseRef = `${remote}/${def}`
133133
if (!refExists(baseRef)) {
134134
logger.success('Skipping validation (no baseline to compare against)')
135-
return null
135+
return undefined
136136
}
137137
return `${baseRef}..${localSha}`
138138
}
@@ -144,7 +144,7 @@ const computeRange = (
144144
const baseRef = `${remote}/${def}`
145145
if (!refExists(baseRef)) {
146146
logger.success('Skipping validation (no baseline for force-push)')
147-
return null
147+
return undefined
148148
}
149149
return `${baseRef}..${localSha}`
150150
}

.oxlintrc.json

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
3-
"plugins": ["typescript", "unicorn", "import"],
3+
"plugins": [
4+
"typescript",
5+
"unicorn",
6+
"import"
7+
],
8+
"jsPlugins": [
9+
"./.config/oxlint-plugin/index.js"
10+
],
411
"categories": {
512
"correctness": "error",
613
"suspicious": "error"
714
},
815
"rules": {
9-
"eslint/curly": ["error", "all"],
16+
"socket/export-top-level-functions": "error",
17+
"socket/no-console-prefer-logger": "error",
18+
"socket/no-dynamic-import-outside-bundle": "error",
19+
"socket/no-fetch-prefer-http-request": "error",
20+
"socket/no-inline-logger": "error",
21+
"socket/no-promise-race-in-loop": "error",
22+
"socket/no-status-emoji": "error",
23+
"socket/no-todo-comments": "error",
24+
"socket/prefer-exists-sync": "error",
25+
"socket/prefer-safe-delete": "error",
26+
"socket/prefer-undefined-over-null": "error",
27+
"socket/sort-set-args": "error",
28+
"socket/sort-source-methods": "error",
29+
"eslint/curly": [
30+
"error",
31+
"all"
32+
],
1033
"eslint/no-await-in-loop": "off",
1134
"eslint/no-console": "off",
1235
"eslint/no-control-regex": "off",
13-
"eslint/no-empty": ["error", { "allowEmptyCatch": true }],
36+
"eslint/no-empty": [
37+
"error",
38+
{
39+
"allowEmptyCatch": true
40+
}
41+
],
1442
"eslint/no-new": "error",
1543
"eslint/no-unmodified-loop-condition": "off",
1644
"eslint/no-useless-catch": "off",
@@ -26,15 +54,27 @@
2654
"import/no-named-as-default-member": "off",
2755
"import/no-self-import": "error",
2856
"import/no-unassigned-import": "off",
29-
"typescript/array-type": ["error", { "default": "array-simple" }],
57+
"typescript/array-type": [
58+
"error",
59+
{
60+
"default": "array-simple"
61+
}
62+
],
3063
"typescript/no-extraneous-class": "off",
3164
"typescript/consistent-type-assertions": [
3265
"error",
33-
{ "assertionStyle": "as" }
66+
{
67+
"assertionStyle": "as"
68+
}
3469
],
3570
"typescript/no-misused-new": "error",
3671
"typescript/no-non-null-asserted-optional-chain": "off",
37-
"typescript/no-this-alias": ["error", { "allowDestructuring": true }],
72+
"typescript/no-this-alias": [
73+
"error",
74+
{
75+
"allowDestructuring": true
76+
}
77+
],
3878
"unicorn/consistent-function-scoping": "off",
3979
"unicorn/no-array-for-each": "off",
4080
"unicorn/no-array-sort": "off",

packages/build-infra/lib/github-releases.mts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export async function getLatestRelease(
128128
if (!quiet) {
129129
logger.info(` No releases found for ${owner}/${repo}`)
130130
}
131-
return null
131+
return undefined
132132
}
133133
const tag = releases[0].tag_name
134134
if (!quiet) {
@@ -152,7 +152,7 @@ export async function getLatestRelease(
152152
if (!quiet) {
153153
logger.info(` No ${prefix} release found in latest 100 releases`)
154154
}
155-
return null
155+
return undefined
156156
},
157157
{
158158
backoffFactor: 2,

0 commit comments

Comments
 (0)