UNPKG

@travetto/compiler

Version:

The compiler infrastructure for the Travetto framework

119 lines (103 loc) 4.41 kB
// @trv-no-transform import fs from 'node:fs/promises'; import type { ManifestContext } from '@travetto/manifest'; import type { CompilerMode, CompilerServerInfo } from './types.ts'; import { Log } from './log.ts'; import { CompilerSetup } from './setup.ts'; import { CompilerServer } from './server/server.ts'; import { CompilerRunner } from './server/runner.ts'; import { CompilerClient } from './server/client.ts'; import { CommonUtil } from './util.ts'; // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export const main = (ctx: ManifestContext) => { const client = new CompilerClient(ctx, Log.scoped('client')); const buildFolders = [ctx.build.outputFolder, ctx.build.compilerFolder, ctx.build.typesFolder]; Log.root = ctx.workspace.path; Log.initLevel('error'); /** Main entry point for compilation */ const compile = async (op: CompilerMode, setupOnly = false): Promise<void> => { const server = await new CompilerServer(ctx, op).listen(); const log = Log.scoped('main'); // Wait for build to be ready if (server) { log.debug('Start Server'); await server.processEvents(async function* (signal) { const changed = await CompilerSetup.setup(ctx); if (!setupOnly) { yield* CompilerRunner.runProcess(ctx, changed, op, signal); } }); log.debug('End Server'); } else { log.info('Server already running, waiting for initial compile to complete'); const ctrl = new AbortController(); Log.consumeProgressEvents(() => client.fetchEvents('progress', { until: ev => !!ev.complete, signal: ctrl.signal })); await client.waitForState(['compile-end', 'watch-start'], 'Successfully built'); ctrl.abort(); } }; const ops = { /** Stop the server */ async stop(): Promise<void> { if (await client.stop()) { console.log(`Stopped server ${ctx.workspace.path}: ${client}`); } else { console.log(`Server not running ${ctx.workspace.path}: ${client}`); } }, /** Restart the server */ async restart(): Promise<void> { await client.stop().then(() => ops.watch()); }, /** Get server info */ info: (): Promise<CompilerServerInfo | undefined> => client.info(), /** Clean the server */ async clean(): Promise<void> { if (await client.clean()) { return console.log(`Clean triggered ${ctx.workspace.path}:`, buildFolders); } else { try { await Promise.all(buildFolders.map(f => fs.rm(CommonUtil.resolveWorkspace(ctx, f), { force: true, recursive: true }))); } catch { } return console.log(`Cleaned ${ctx.workspace.path}:`, buildFolders); } }, /** Stream events */ events: async (type: string, handler: (ev: unknown) => unknown): Promise<void> => { if (type === 'change' || type === 'log' || type === 'progress' || type === 'state' || type === 'all') { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions for await (const ev of client.fetchEvents(type as 'change')) { await handler(ev); } } else { throw new Error(`Unknown event type: ${type}`); } }, /** Build the project */ async build(): Promise<void> { Log.initLevel('info'); await compile('build'); }, /** Build and watch the project */ async watch(): Promise<void> { Log.initLevel('info'); await compile('watch'); }, /** Set arguments and import module */ async exec(mod: string, args?: string[]): Promise<unknown> { Log.initLevel('none'); if (!(await client.isWatching())) { // Short circuit if we can Log.initLevel('error'); await compile('build'); } process.env.TRV_MANIFEST = CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', ctx.main.name); // Setup for running if (args) { process.argv = [process.argv0, mod, ...args]; } return import(CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', mod)); // Return function to run import on a module }, /** Manifest entry point */ async manifest(output?: string, prod?: boolean): Promise<void> { await compile('build', true); await CompilerSetup.exportManifest(ctx, output, prod); return; } }; return ops; }; export type Operations = ReturnType<typeof main>;