Files
recflare/packages/tools/src/tsconfig.ts
T
Devin Zuczek 8e644a5c20 Initial commit
2026-06-08 18:23:40 -04:00

67 lines
1.7 KiB
TypeScript

import path from 'node:path'
import { inspect } from 'node:util'
import type {
createProgram,
parseJsonConfigFileContent,
readConfigFile,
sys,
CompilerOptions as TSCompilerOptions,
} from 'typescript'
export type { TSCompilerOptions }
interface TSModule {
readConfigFile: typeof readConfigFile
parseJsonConfigFileContent: typeof parseJsonConfigFileContent
sys: typeof sys
createProgram: typeof createProgram
}
/**
* TypeScript helpers. This is a class so that we can dynamically import the TypeScript module
* to reduce runx start time for commands that don't use the typescript package.
*
* @example
*
* ```ts
* const tsHelpers = await new TSHelpers().init()
* const { ts } = tsHelpers
* const tsConfig = tsHelpers.getTSConfig()
* ts.createProgram(entryPoints, tsConfig).emit()
* ```
*/
export class TSHelpers {
#ts: TSModule | undefined
public get ts(): TSModule {
if (!this.#ts) {
throw new Error('TSHelpers not initialized. Call init() first.')
}
return this.#ts
}
async init(): Promise<TSHelpers> {
this.#ts = (await import('typescript')) as TSModule
return this
}
getTSConfig(configPath = 'tsconfig.json'): TSCompilerOptions {
const absolutePath = path.resolve(configPath)
const configFile = this.ts.readConfigFile(absolutePath, (p) => this.ts.sys.readFile(p))
if (configFile.error) {
throw new Error(`Failed to read tsconfig: ${inspect(configFile.error)}`)
}
const parsed = this.ts.parseJsonConfigFileContent(
configFile.config,
this.ts.sys,
path.dirname(absolutePath)
)
if (parsed.errors.length > 0) {
throw new Error(`Failed to parse tsconfig: ${inspect(parsed.errors)}`)
}
return parsed.options
}
}