| ... | ... | @@ -9,6 +9,17 @@ import * as Predicate from "effect/Predicate"; |
| 9 | 9 | import * as Schema from "effect/Schema"; |
| 10 | 10 | import * as Stream from "effect/Stream"; |
| 11 | 11 | import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; |
| 12 | import * as NodeModule from "node:module"; |
| 13 | |
| 14 | // oxlint is only a transitive dependency (via vite-plus), so its bin placement |
| 15 | // varies by package manager: pnpm hoists it into the virtual store, while |
| 16 | // other layouts expose vite-plus's LSP-only wrapper instead. Resolve the real |
| 17 | // package through vite-plus rather than hardcoding either layout, and do it at |
| 18 | // module scope so a broken install fails once with a resolution error instead |
| 19 | // of as an opaque defect in every test. |
| 20 | const oxlintPackageJsonPath = NodeModule.createRequire( |
| 21 | NodeModule.createRequire(import.meta.url).resolve("vite-plus/package.json"), |
| 22 | ).resolve("oxlint/package.json"); |
| 12 | 23 | |
| 13 | 24 | class OxlintFixtureFailure extends Data.TaggedError("OxlintFixtureFailure")<{ |
| 14 | 25 | readonly exitCode: number; |
| ... | ... | @@ -93,14 +104,7 @@ export const createOxlintRuleHarness = ( |
| 93 | 104 | const configPath = path.join(fixtureDir, ".oxlintrc.json"); |
| 94 | 105 | const sourcePath = path.join(fixtureDir, options.filename ?? "fixture.ts"); |
| 95 | 106 | const repoRoot = path.join(import.meta.dirname, "..", ".."); |
| 96 | | const oxlintBin = path.join( |
| 97 | | repoRoot, |
| 98 | | "node_modules", |
| 99 | | ".pnpm", |
| 100 | | "node_modules", |
| 101 | | ".bin", |
| 102 | | "oxlint", |
| 103 | | ); |
| 107 | const oxlintBin = path.join(path.dirname(oxlintPackageJsonPath), "bin", "oxlint"); |
| 104 | 108 | const pluginPath = path.join(repoRoot, "oxlint-plugin-t3code", "index.ts"); |
| 105 | 109 | |
| 106 | 110 | yield* fs.writeFileString( |
| ... | ... | @@ -112,8 +116,13 @@ export const createOxlintRuleHarness = ( |
| 112 | 116 | ); |
| 113 | 117 | yield* fs.writeFileString(sourcePath, source); |
| 114 | 118 | |
| 119 | // Run through the current Node binary: oxlint's bin is an extensionless |
| 120 | // shebang script, which Windows cannot spawn directly and which would |
| 121 | // otherwise pick up whatever node is first on PATH. |
| 115 | 122 | const output = yield* spawnAndCollectOutput( |
| 116 | | ChildProcess.make(oxlintBin, ["--config", configPath, sourcePath], { cwd: repoRoot }), |
| 123 | ChildProcess.make(process.execPath, [oxlintBin, "--config", configPath, sourcePath], { |
| 124 | cwd: repoRoot, |
| 125 | }), |
| 117 | 126 | ); |
| 118 | 127 | |
| 119 | 128 | if (output.exitCode !== 0) { |