Skip to content

Commit f23bfbc

Browse files
authored
fix: respect project paths and Vite+ build commands (#581)
1 parent 9cef6a8 commit f23bfbc

15 files changed

Lines changed: 170 additions & 19 deletions

File tree

‎packages/kit/src/node/utils.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import type { ClientScriptEntry } from '../types/docks'
22
import { Buffer } from 'node:buffer'
3+
import { isPackageExists } from 'local-pkg'
4+
5+
/** Detect Vite+ from the project directory when selecting its toolchain commands. */
6+
export function isVitePlusInstalled(cwd: string): boolean {
7+
return isPackageExists('vite-plus', { paths: [cwd] })
8+
}
39

410
function toDataURL(code: string) {
511
return `data:text/javascript;base64,${Buffer.from(code).toString('base64')}`
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { DevframeNodeContext } from 'devframe/types'
2+
import type { ServerFunctions } from '../rpc'
3+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
4+
import { tmpdir } from 'node:os'
5+
import { join } from 'pathe'
6+
import { RpcFunctionsCollectorBase } from 'devframe/rpc'
7+
import { afterEach, describe, expect, it } from 'vitest'
8+
import { oxcDevframe } from '../devframe'
9+
10+
const fixtures: string[] = []
11+
12+
afterEach(async () => {
13+
await Promise.all(fixtures.splice(0).map(dir => rm(dir, { recursive: true, force: true })))
14+
})
15+
16+
async function createProject() {
17+
const workspaceRoot = await mkdtemp(join(tmpdir(), 'oxc-monorepo-'))
18+
fixtures.push(workspaceRoot)
19+
const cwd = join(workspaceRoot, 'packages/app')
20+
await mkdir(cwd, { recursive: true })
21+
const ctx = { cwd, workspaceRoot } as DevframeNodeContext
22+
const rpc = new RpcFunctionsCollectorBase<ServerFunctions, DevframeNodeContext>(ctx)
23+
ctx.rpc = rpc as unknown as DevframeNodeContext['rpc']
24+
await oxcDevframe.setup!(ctx, {} as never)
25+
return { cwd, workspaceRoot, rpc }
26+
}
27+
28+
describe('Oxc project context', () => {
29+
it('discovers and reads the project configs when the workspace has its own configs', async () => {
30+
const { cwd, workspaceRoot, rpc } = await createProject()
31+
const configs = [
32+
['oxlint.config.ts', 'devtools-oxc:get-lint-config-file'],
33+
['oxfmt.config.ts', 'devtools-oxc:get-fmt-config-file'],
34+
] as const
35+
for (const [filename] of configs) {
36+
await writeFile(join(workspaceRoot, filename), 'export default { /* workspace */ }')
37+
await writeFile(join(cwd, filename), 'export default { /* project */ }')
38+
}
39+
40+
const discover = await rpc.getHandler('devtools-oxc:get-config-files')
41+
const files = await discover()
42+
expect(files).toEqual(
43+
expect.arrayContaining(
44+
configs.map(([path]) =>
45+
expect.objectContaining({
46+
path,
47+
content: 'export default { /* project */ }',
48+
}),
49+
),
50+
),
51+
)
52+
expect(files).toHaveLength(2)
53+
for (const [, name] of configs) {
54+
const readConfig = await rpc.getHandler(name)
55+
await expect(readConfig()).resolves.toBe('export default { /* project */ }')
56+
}
57+
})
58+
})
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { DevframeNodeContext } from 'devframe/types'
2+
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
3+
import { tmpdir } from 'node:os'
4+
import { join } from 'pathe'
5+
import { launchEditor } from 'devframe/utils/launch-editor'
6+
import { afterEach, describe, expect, it, vi } from 'vitest'
7+
import { openInEditor } from '../rpc/functions/open-in-editor'
8+
import { oxfmtGetConfigFile } from '../rpc/functions/oxfmt-get-config-file'
9+
import { oxlintGetConfigFile } from '../rpc/functions/oxlint-get-config-file'
10+
11+
vi.mock('devframe/utils/launch-editor', () => ({ launchEditor: vi.fn<typeof launchEditor>() }))
12+
13+
const fixtures: string[] = []
14+
15+
afterEach(async () => {
16+
vi.clearAllMocks()
17+
await Promise.all(fixtures.splice(0).map(dir => rm(dir, { recursive: true, force: true })))
18+
})
19+
20+
describe('project-relative RPC paths', () => {
21+
it.each(['', ':12', ':12:3'])('opens project files with position suffix "%s"', async suffix => {
22+
const cwd = join(tmpdir(), 'oxc-workspace')
23+
const { handler } = openInEditor.setup({ cwd } as DevframeNodeContext)
24+
25+
await handler(`src/index.ts${suffix}`)
26+
27+
expect(launchEditor).toHaveBeenCalledWith(join(cwd, `src/index.ts${suffix}`))
28+
})
29+
30+
it('preserves absolute editor targets', async () => {
31+
const { handler } = openInEditor.setup({ cwd: '/workspace' } as DevframeNodeContext)
32+
const target = join(tmpdir(), 'external/index.ts:12:3')
33+
34+
await handler(target)
35+
36+
expect(launchEditor).toHaveBeenCalledWith(target)
37+
})
38+
39+
it.each([
40+
['oxlint.config.ts', oxlintGetConfigFile],
41+
['oxfmt.config.ts', oxfmtGetConfigFile],
42+
] as const)('reads %s from the context directory', async (filename, definition) => {
43+
const cwd = await mkdtemp(join(tmpdir(), 'oxc-workspace-config-'))
44+
fixtures.push(cwd)
45+
const content = 'export default { /* workspace config */ }'
46+
await writeFile(join(cwd, filename), content)
47+
const { handler } = definition.setup({ cwd } as DevframeNodeContext)
48+
49+
await expect(handler()).resolves.toBe(content)
50+
await rm(join(cwd, filename))
51+
await expect(handler()).resolves.toBeNull()
52+
})
53+
})

‎packages/oxc/src/node/rpc/functions/open-in-editor.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { launchEditor } from 'devframe/utils/launch-editor'
2+
import { resolve } from 'pathe'
23
import { defineOxcRpc } from '../_define'
34

45
/**
@@ -10,10 +11,10 @@ import { defineOxcRpc } from '../_define'
1011
export const openInEditor = defineOxcRpc({
1112
name: 'devtools-oxc:open-in-editor',
1213
type: 'action',
13-
setup: () => {
14+
setup: context => {
1415
return {
1516
handler: async (target: string) => {
16-
launchEditor(target)
17+
launchEditor(resolve(context.cwd, target))
1718
},
1819
}
1920
},

‎packages/oxc/src/node/rpc/functions/overview.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { isVitePlusInstalled } from '@vitejs/devtools-kit/node'
12
import { defineOxcRpc } from '../_define'
23
import { x } from 'tinyexec'
3-
import { getVitePlusVersions, isVitePlusInstalled } from '../../utils/vite-plus'
4+
import { getVitePlusVersions } from '../../utils/vite-plus'
45
import { needsOxlintMigration } from './oxlint-setup'
56

67
type Package = {

‎packages/oxc/src/node/rpc/functions/oxfmt-get-config-file.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ export const oxfmtGetConfigFile = defineOxcRpc({
66
type: 'query',
77
jsonSerializable: true,
88
cacheable: true,
9-
setup: () => {
9+
setup: context => {
1010
return {
1111
handler: async () => {
12-
const config = await getOxfmtConfig()
12+
const config = await getOxfmtConfig(context.cwd)
1313
return config
1414
},
1515
}

‎packages/oxc/src/node/rpc/functions/oxfmt-run.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { isVitePlusInstalled } from '@vitejs/devtools-kit/node'
12
import { existsSync } from 'node:fs'
23
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'
34
import { Diagnostic } from 'nostics'
45
import { resolve } from 'pathe'
56
import { x } from 'tinyexec'
67
import { diagnostics } from '../../diagnostics'
7-
import { isVitePlusInstalled } from '../../utils/vite-plus'
88
import { ensureOxcGitignored } from '../../utils/oxlint'
99
import { defineOxcRpc } from '../_define'
1010
import { isGitDirty } from './oxfmt-setup'

‎packages/oxc/src/node/rpc/functions/oxlint-get-config-file.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ export const oxlintGetConfigFile = defineOxcRpc({
66
type: 'query',
77
jsonSerializable: true,
88
cacheable: true,
9-
setup: () => {
9+
setup: context => {
1010
return {
1111
handler: async () => {
12-
const config = await getOxlintConfig()
12+
const config = await getOxlintConfig(context.cwd)
1313
return config
1414
},
1515
}

‎packages/oxc/src/node/rpc/functions/oxlint-run.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { isVitePlusInstalled } from '@vitejs/devtools-kit/node'
12
import { Diagnostic } from 'nostics'
23
import { x } from 'tinyexec'
34
import { defineOxcRpc } from '../_define'
45
import { diagnostics } from '../../diagnostics'
56
import { getOxcConfigFiles } from '../../utils/config-files'
67
import { ensureOxcGitignored, parseOxlintOutput } from '../../utils/oxlint'
7-
import { getVitePlusVersions, isVitePlusInstalled } from '../../utils/vite-plus'
8+
import { getVitePlusVersions } from '../../utils/vite-plus'
89
import { getLintResultsManager } from '../utils'
910

1011
export const oxlintRun = defineOxcRpc({

‎packages/oxc/src/node/utils/oxfmt.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { readFile } from 'node:fs/promises'
22
import { cwd } from 'node:process'
33
import { resolve } from 'pathe'
44

5-
export async function getOxfmtConfig() {
6-
const configPath = resolve(cwd(), 'oxfmt.config.ts')
5+
export async function getOxfmtConfig(root = cwd()) {
6+
const configPath = resolve(root, 'oxfmt.config.ts')
77
try {
88
const config = await readFile(configPath, 'utf-8')
99
return config

0 commit comments

Comments
 (0)