Files
orca/config/scripts/check-mobile-shared-dependency-versions.mjs
T
Neil cc2b6fe6a2 build(mobile): move to TypeScript 7 and Vitest 5, typecheck through the root tsrs runner (#33419)
- Bump mobile typescript to ^7.0.2 and vitest to 5.0.5; keep TypeScript 6 as typescript-api
  for the test-support code that walks the AST, mirroring the root.
- Patch Expo CLI's tsconfig reader to fall back to typescript-api: TypeScript 7 has no
  compiler API, and Metro otherwise crashes reading tsconfig paths.
- Register mobile/tsconfig.json and mobile/tsconfig.test.json with the root typecheck runner;
  locally they use incremental tsrs (Bun elsewhere), CI uses Bun like root CI.
- Route the tests-typecheck ratchet through the same compiler selection.
- Enforce root/mobile parity for typescript, typescript-api and vitest.
2026-10-24 23:09:20 -07:00

65 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
// Root and mobile are separate pnpm projects, so nothing else stops their lockfiles drifting apart.
import { readFileSync } from 'node:fs'
import { join, resolve } from 'node:path'
import { pathToFileURL } from 'node:url'
import { lockedVersion, lockfileRootImporter } from './pnpm-lockfile-root-importer.mjs'
// The packages src/shared imports that mobile/tsconfig.json remaps to mobile's copy. TypeScript
// merges two copies only at the same version; else zod-wrapped schemas infer `{}` (phone-feed-list.ts).
export const SHARED_DEPENDENCIES = ['zod', 'tweetnacl', '@noble/hashes', '@types/ws']
// Mobile typechecks through the root runner, whose Bun path accepts one TypeScript version, and
// mobile CI runs its tests with the root's Vitest CLI against mobile's `vitest` imports.
export const TOOLCHAIN_DEPENDENCIES = ['typescript', 'typescript-api', 'vitest']
const CHECKED_DEPENDENCIES = [...SHARED_DEPENDENCIES, ...TOOLCHAIN_DEPENDENCIES]
function importerVersion(importer, name) {
return lockedVersion(importer.dependencies?.[name] ?? importer.devDependencies?.[name])
}
export function findSharedDependencyVersionProblems({
rootImporter,
mobileImporter,
names = CHECKED_DEPENDENCIES
}) {
const problems = []
for (const name of names) {
const root = importerVersion(rootImporter, name)
const mobile = importerVersion(mobileImporter, name)
if (!root || !mobile) {
problems.push(`${name} is not a direct dependency of ${root ? 'mobile' : 'the root'}`)
} else if (root !== mobile) {
problems.push(`${name}: the root locks ${root}, mobile locks ${mobile}`)
}
}
return problems
}
export function main(root = resolve(import.meta.dirname, '../..')) {
const readImporter = (lockfile) =>
lockfileRootImporter(readFileSync(join(root, lockfile), 'utf8'))
const problems = findSharedDependencyVersionProblems({
rootImporter: readImporter('pnpm-lock.yaml'),
mobileImporter: readImporter(join('mobile', 'pnpm-lock.yaml'))
})
if (problems.length > 0) {
console.error('Root and mobile must lock the same version of:')
for (const problem of problems) {
console.error(`- ${problem}`)
}
console.error(
'Set the same range in package.json and mobile/package.json, then pnpm install in both.'
)
return 1
}
console.log(`Root and mobile lock the same ${CHECKED_DEPENDENCIES.join(', ')}.`)
return 0
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
process.exit(main())
}