Skip to content

Commit 04c4d87

Browse files
committed
fix(lint): re-cascade canonical oxlint plugin rules — undo self-corruption
The most recent `lint --fix` autofix pass ran the plugin rules against their own source files and rewrote the match tables in place. The shape of the corruption per rule: * `no-npx-dlx.mts`: PATTERNS table flipped from `['npx ', 'pnpm exec ']` / `['pnpm dlx ', 'pnpm exec ']` to `['pnpm exec ', 'pnpm exec ']` — causing the rule to flag every `pnpm exec` reference (~117 false positives in socket-cli alone). * `inclusive-language.mts`: SUBSTITUTIONS table flipped from `['whitelist', 'allowlist']` / `['grandfathered', 'legacy']` / `['dummy', 'placeholder']` to `['allowlist', 'allowlist']` / `['legacy', 'legacy']` / `['placeholder', 'placeholder']` — causing the rule to scan FOR its own replacements (~217 false positives). Re-cascaded all 12 plugin rule files from `socket-wheelhouse/template/. config/oxlint-plugin/rules/`. Real lint counts dropped sharply (cli's inclusive-language: 252 → 35; no-npx-dlx: 117 → 10). Underlying defect to fix in a follow-up: the plugin rule files should be excluded from the autofix surface (they're self-referential by design).
1 parent a83f450 commit 04c4d87

13 files changed

Lines changed: 86 additions & 86 deletions

.config/oxlint-plugin/rules/_inject-import.mts

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,6 @@
1212
* insertion safely — only one survives.
1313
*/
1414

15-
/**
16-
* Build the fixer-side inserts for missing import + optional hoist.
17-
* Returns an array of fixer operations the caller appends to its own
18-
* fix() return value.
19-
*
20-
* summary — output of summarizeImportTarget()
21-
* fixer — the fixer passed to context.report({ fix })
22-
* importLine — the literal `import { ... } from '...'` text
23-
* hoistLine — optional; the literal `const x = ...()` text
24-
*/
25-
export function appendImportFixes(summary, fixer, importLine, hoistLine) {
26-
const ops = []
27-
if (!summary.hasImport) {
28-
if (summary.lastImport) {
29-
ops.push(fixer.insertTextAfter(summary.lastImport, `\n${importLine}`))
30-
} else {
31-
ops.push(fixer.insertTextBeforeRange([0, 0], `${importLine}\n`))
32-
}
33-
}
34-
if (hoistLine && !summary.hasLocal) {
35-
if (summary.lastImport) {
36-
ops.push(fixer.insertTextAfter(summary.lastImport, `\n\n${hoistLine}`))
37-
} else {
38-
ops.push(fixer.insertTextBeforeRange([0, 0], `${hoistLine}\n\n`))
39-
}
40-
}
41-
return ops
42-
}
43-
4415
/**
4516
* Walk a Program node body once and figure out:
4617
* - the last top-level ImportDeclaration node (or undefined)
@@ -108,3 +79,32 @@ export function summarizeImportTarget(
10879
}
10980
return { hasImport, hasLocal, lastImport }
11081
}
82+
83+
/**
84+
* Build the fixer-side inserts for missing import + optional hoist.
85+
* Returns an array of fixer operations the caller appends to its own
86+
* fix() return value.
87+
*
88+
* summary — output of summarizeImportTarget()
89+
* fixer — the fixer passed to context.report({ fix })
90+
* importLine — the literal `import { ... } from '...'` text
91+
* hoistLine — optional; the literal `const x = ...()` text
92+
*/
93+
export function appendImportFixes(summary, fixer, importLine, hoistLine) {
94+
const ops = []
95+
if (!summary.hasImport) {
96+
if (summary.lastImport) {
97+
ops.push(fixer.insertTextAfter(summary.lastImport, `\n${importLine}`))
98+
} else {
99+
ops.push(fixer.insertTextBeforeRange([0, 0], `${importLine}\n`))
100+
}
101+
}
102+
if (hoistLine && !summary.hasLocal) {
103+
if (summary.lastImport) {
104+
ops.push(fixer.insertTextAfter(summary.lastImport, `\n\n${hoistLine}`))
105+
} else {
106+
ops.push(fixer.insertTextBeforeRange([0, 0], `${hoistLine}\n\n`))
107+
}
108+
}
109+
return ops
110+
}

.config/oxlint-plugin/rules/export-top-level-functions.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const SCRIPT_ENTRY_NAMES = new Set(['main'])
3333
* declarations only via `Program > FunctionDeclaration`; an
3434
* `ExportNamedDeclaration` wraps them in a different shape).
3535
*/
36-
export function collectExportedNames(program) {
36+
function collectExportedNames(program) {
3737
const exported = new Set()
3838
for (const stmt of program.body) {
3939
if (stmt.type === 'ExportNamedDeclaration' && !stmt.declaration) {

.config/oxlint-plugin/rules/inclusive-language.mts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const REPORT_ONLY_TERMS = ['master', 'slave']
5656
const BYPASS_RE = /inclusive-language:\s*external-api/
5757

5858
/** Build a regex matching any legacy stem with word boundaries. */
59-
export function buildDetectorRegex() {
59+
function buildDetectorRegex() {
6060
const stems = [
6161
...SUBSTITUTIONS.map(([legacy]) => legacy),
6262
...REPORT_ONLY_TERMS,
@@ -72,7 +72,7 @@ const DETECTOR_RE = buildDetectorRegex()
7272
* the new stem. Returns undefined when there's no autofix-able
7373
* substitution (master/slave).
7474
*/
75-
export function rewriteHit(match) {
75+
function rewriteHit(match) {
7676
const lower = match.toLowerCase()
7777
for (const [legacy, replacement] of SUBSTITUTIONS) {
7878
if (!lower.startsWith(legacy)) {
@@ -93,7 +93,7 @@ export function rewriteHit(match) {
9393
return undefined
9494
}
9595

96-
export function findHits(text) {
96+
function findHits(text) {
9797
const hits = []
9898
DETECTOR_RE.lastIndex = 0
9999
let m

.config/oxlint-plugin/rules/no-npx-dlx.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const rule = {
135135
if (next === value) {
136136
// Defensive — if our replace-all became a no-op, don't
137137
// ship an empty fix.
138-
return undefined
138+
return null
139139
}
140140
// Preserve the original quote style.
141141
const raw = sourceCode.getText(node)

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

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

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

2525
const LOOP_TYPES = new Set([
26-
'DoWhileStatement',
27-
'ForInStatement',
28-
'ForOfStatement',
2926
'ForStatement',
27+
'ForOfStatement',
28+
'ForInStatement',
3029
'WhileStatement',
30+
'DoWhileStatement',
3131
])
3232

33-
export function isInsideLoop(node) {
33+
function isInsideLoop(node) {
3434
let current = node.parent
3535
while (current) {
3636
if (LOOP_TYPES.has(current.type)) {

.config/oxlint-plugin/rules/prefer-async-spawn.mts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@
4343
*/
4444

4545
const CHILD_PROCESS_SPECIFIERS = new Set([
46-
'child_process',
4746
'node:child_process',
47+
'child_process',
4848
])
4949

5050
const LIB_SPECIFIER = '@socketsecurity/lib/spawn'
5151

52-
const BANNED_NAMES = new Set(['spawn', 'spawnSync'])
52+
const BANNED_NAMES = new Set(['spawnSync', 'spawn'])
5353

5454
const BYPASS_RE = /prefer-async-spawn:\s*sync-required/
5555

@@ -131,7 +131,7 @@ const rule = {
131131
BANNED_NAMES.has(s.imported.name),
132132
)
133133
if (banned.length === 0) {
134-
return undefined
134+
return null
135135
}
136136
const others = node.specifiers.filter(
137137
s =>
@@ -142,7 +142,7 @@ const rule = {
142142
if (others.length > 0) {
143143
// Mixed line — leave it alone; a partial rewrite could lose
144144
// the non-banned import.
145-
return undefined
145+
return null
146146
}
147147
// The lib re-exports `spawn` (and the user can wire `as
148148
// spawnSync` themselves if they really need a name). For the

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
import { appendImportFixes, summarizeImportTarget } from './_inject-import.mts'
3434

3535
const ACCESS_METHODS = new Set(['access', 'accessSync'])
36-
const STAT_METHODS = new Set(['lstat', 'lstatSync', 'stat', 'statSync'])
37-
const WRAPPER_NAMES = new Set(['fileExists', 'isDir', 'isFile', 'pathExists'])
36+
const STAT_METHODS = new Set(['stat', 'statSync', 'lstat', 'lstatSync'])
37+
const WRAPPER_NAMES = new Set(['fileExists', 'pathExists', 'isFile', 'isDir'])
3838

3939
const EXISTS_SYNC_IMPORT_LINE = "import { existsSync } from 'node:fs'"
4040

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ import { appendImportFixes, summarizeImportTarget } from './_inject-import.mts'
3636
const DELETE_METHODS = new Set([
3737
'rm',
3838
'rmSync',
39-
'rmdir',
40-
'rmdirSync',
4139
'unlink',
4240
'unlinkSync',
41+
'rmdir',
42+
'rmdirSync',
4343
])
4444

45-
const SYNC_METHODS = new Set(['rmSync', 'rmdirSync', 'unlinkSync'])
45+
const SYNC_METHODS = new Set(['rmSync', 'unlinkSync', 'rmdirSync'])
4646

4747
/** @type {import('eslint').Rule.RuleModule} */
4848
const rule = {

.config/oxlint-plugin/rules/socket-api-token-env.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424

2525
const LEGACY_ALIASES = new Set([
2626
'SOCKET_API_KEY',
27-
'SOCKET_SECURITY_API_KEY',
2827
'SOCKET_SECURITY_API_TOKEN',
28+
'SOCKET_SECURITY_API_KEY',
2929
])
3030

3131
const CANONICAL = 'SOCKET_API_TOKEN'

.config/oxlint-plugin/rules/sort-named-imports.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ const rule = {
131131
filter: t => t.value === '}',
132132
})
133133
if (!openBrace || !closeBrace) {
134-
return undefined
134+
return null
135135
}
136136
const sliceStart = openBrace.range[1]
137137
const sliceEnd = closeBrace.range[0]

0 commit comments

Comments
 (0)