mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
* Use incremental tsrs for local typechecks * Update pinned Bun to 1.4.4 * fix(deps): bump dompurify to 3.4.17 and docs next to 16.4.1 for security advisories dompurify 3.4.17 patches GHSA-cg2g-xh64-v4q7, GHSA-mrv2-3pqr-j5jr and GHSA-c6gr-qvv4-5v3f in the root and mobile lockfiles. next 16.4.1 patches GHSA-2464-fhr4-w9xw, GHSA-673q-mjm6-r5xr and GHSA-p3m5-59mp-jv5r in the docs site. * Prepare mobile bundle for smoke benchmarks * Give native compiler benchmarks a larger ARM runner --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
218 lines
6.7 KiB
JavaScript
218 lines
6.7 KiB
JavaScript
import {
|
|
mkdirSync,
|
|
existsSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
readdirSync,
|
|
rmSync,
|
|
symlinkSync,
|
|
writeFileSync
|
|
} from 'node:fs'
|
|
import { availableParallelism, tmpdir } from 'node:os'
|
|
import { join, resolve } from 'node:path'
|
|
import { runProcess, runProcessSync } from '@orca/process-host'
|
|
import { afterEach, expect, it, vi } from 'vitest'
|
|
import { buildCli } from './build-cli.mjs'
|
|
import { resolvePinnedBunExecutable } from './pinned-bun-executable.mjs'
|
|
import { resolveProjectCompiler } from './run-typecheck-projects-in-parallel.mjs'
|
|
import { supportsTsrs } from './tsrs-typecheck-compiler.mjs'
|
|
|
|
const ROOT = process.cwd()
|
|
const resolveBunExecutable = () => resolvePinnedBunExecutable(ROOT, runProcessSync)
|
|
const directories = []
|
|
afterEach(() => {
|
|
for (const directory of directories.splice(0)) {
|
|
rmSync(directory, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
function fixture() {
|
|
const root = mkdtempSync(join(tmpdir(), 'orca-cli-build-'))
|
|
directories.push(root)
|
|
mkdirSync(join(root, 'config'))
|
|
mkdirSync(join(root, 'src'))
|
|
symlinkSync(resolve('node_modules'), join(root, 'node_modules'), 'junction')
|
|
writeFileSync(join(root, 'package.json'), '{"type":"commonjs"}')
|
|
writeFileSync(join(root, 'config', '.bun-version'), readFileSync('config/.bun-version'))
|
|
writeFileSync(
|
|
join(root, 'config', 'tsconfig.build.cli.json'),
|
|
JSON.stringify({
|
|
compilerOptions: {
|
|
module: 'Node20',
|
|
moduleResolution: 'Node16',
|
|
target: 'ES2022',
|
|
strict: true,
|
|
types: [],
|
|
rootDir: '../src',
|
|
declaration: true,
|
|
declarationMap: true,
|
|
sourceMap: true
|
|
},
|
|
include: ['../src/**/*.ts']
|
|
})
|
|
)
|
|
writeFileSync(join(root, 'src', 'constants.ts'), 'export const enum Mode { Ready = 7 }\n')
|
|
writeFileSync(
|
|
join(root, 'src', 'entry.ts'),
|
|
`import { Mode } from './constants'
|
|
export interface Item { value: number }
|
|
export const item: Item = { value: Mode.Ready }
|
|
`
|
|
)
|
|
return root
|
|
}
|
|
|
|
it('checks the emit project first, retains all CPU cores and preserves the TypeScript emitter', async () => {
|
|
const order = []
|
|
const check = vi.fn(async () => {
|
|
order.push('check')
|
|
return []
|
|
})
|
|
const execute = vi.fn(async () => {
|
|
order.push('emit')
|
|
return { code: 0 }
|
|
})
|
|
await buildCli({ check, execute, resolveBunExecutable: () => 'pinned-bun' })
|
|
expect(order).toEqual(['check', 'emit'])
|
|
expect(check).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
compiler: 'bun',
|
|
bunExecutable: 'pinned-bun',
|
|
projects: [{ config: 'config/tsconfig.build.cli.json', heapGib: 2 }],
|
|
bunThreads: availableParallelism()
|
|
})
|
|
)
|
|
expect(execute).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
program: process.execPath,
|
|
args: [
|
|
resolveProjectCompiler('config/tsconfig.build.cli.json'),
|
|
'-p',
|
|
'config/tsconfig.build.cli.json',
|
|
'--outDir',
|
|
'out',
|
|
'--composite',
|
|
'false',
|
|
'--incremental',
|
|
'false',
|
|
'--noCheck'
|
|
]
|
|
})
|
|
)
|
|
})
|
|
|
|
it('does not emit when checking fails or the pinned Bun is missing', async () => {
|
|
const execute = vi.fn()
|
|
await expect(
|
|
buildCli({
|
|
check: async () => [new Error('type error')],
|
|
execute,
|
|
resolveBunExecutable: () => 'pinned-bun'
|
|
})
|
|
).rejects.toThrow('type error')
|
|
await expect(buildCli({ execute, resolveBunExecutable: () => null })).rejects.toThrow(
|
|
'run pnpm install'
|
|
)
|
|
expect(execute).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('propagates emitter failures', async () => {
|
|
await expect(
|
|
buildCli({
|
|
check: async () => [],
|
|
resolveBunExecutable: () => 'pinned-bun',
|
|
execute: async () => ({ code: null, signal: 'SIGKILL' })
|
|
})
|
|
).rejects.toThrow('signal=SIGKILL')
|
|
})
|
|
|
|
it('rejects unknown compiler selections before emission', async () => {
|
|
const execute = vi.fn()
|
|
await expect(buildCli({ compiler: 'unknown', execute })).rejects.toThrow(
|
|
'Invalid ORCA_CLI_BUILD_COMPILER'
|
|
)
|
|
expect(execute).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('produces byte-identical JavaScript, declarations and maps with the real compilers', async () => {
|
|
const root = fixture()
|
|
const baseline = await runProcess({
|
|
program: process.execPath,
|
|
args: [
|
|
resolveProjectCompiler('config/tsconfig.build.cli.json', root),
|
|
'-p',
|
|
'config/tsconfig.build.cli.json',
|
|
'--outDir',
|
|
'baseline',
|
|
'--composite',
|
|
'false',
|
|
'--incremental',
|
|
'false'
|
|
],
|
|
cwd: root
|
|
})
|
|
expect(baseline.code, baseline.stdout + baseline.stderr).toBe(0)
|
|
await buildCli({ root, outDir: 'optimized', resolveBunExecutable })
|
|
const files = readdirSync(join(root, 'baseline')).sort()
|
|
expect(readdirSync(join(root, 'optimized')).sort()).toEqual(files)
|
|
expect(files).toHaveLength(8)
|
|
for (const file of files) {
|
|
expect(
|
|
readFileSync(join(root, 'optimized', file)).equals(
|
|
readFileSync(join(root, 'baseline', file))
|
|
),
|
|
file
|
|
).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('blocks output for real type errors and rejects compiler version drift', async () => {
|
|
const root = fixture()
|
|
writeFileSync(join(root, 'src', 'entry.ts'), 'export const value: number = "wrong"\n')
|
|
const execute = vi.fn()
|
|
await expect(buildCli({ root, execute, resolveBunExecutable })).rejects.toThrow(
|
|
'exited with code 1'
|
|
)
|
|
expect(execute).not.toHaveBeenCalled()
|
|
|
|
const drift = fixture()
|
|
rmSync(join(drift, 'node_modules'))
|
|
mkdirSync(join(drift, 'node_modules', 'typescript'), { recursive: true })
|
|
writeFileSync(
|
|
join(drift, 'node_modules', 'typescript', 'package.json'),
|
|
JSON.stringify({
|
|
name: 'typescript',
|
|
version: '99.0.0',
|
|
bin: { tsc: 'compiler.cjs' }
|
|
})
|
|
)
|
|
await expect(buildCli({ root: drift, execute, resolveBunExecutable })).rejects.toThrow(
|
|
'resolves 99.0.0'
|
|
)
|
|
expect(execute).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it.skipIf(!supportsTsrs())(
|
|
'the optional compiler preserves emitted bytes and blocks output on type errors',
|
|
async () => {
|
|
const root = fixture()
|
|
await buildCli({ root, outDir: 'baseline', compiler: 'bun', resolveBunExecutable })
|
|
await buildCli({ root, outDir: 'optimized', compiler: 'tsrs' })
|
|
const files = readdirSync(join(root, 'baseline')).sort()
|
|
expect(readdirSync(join(root, 'optimized')).sort()).toEqual(files)
|
|
for (const file of files) {
|
|
expect(
|
|
readFileSync(join(root, 'optimized', file)).equals(
|
|
readFileSync(join(root, 'baseline', file))
|
|
),
|
|
file
|
|
).toBe(true)
|
|
}
|
|
writeFileSync(join(root, 'src', 'entry.ts'), 'export const value: number = "wrong"\n')
|
|
await expect(buildCli({ root, outDir: 'failed', compiler: 'tsrs' })).rejects.toThrow(
|
|
'CLI compilation failed'
|
|
)
|
|
expect(existsSync(join(root, 'failed'))).toBe(false)
|
|
}
|
|
)
|