UNPKG

@ibyar/cli

Version:

The Ibyar/Aurora CLI tool

179 lines 7.47 kB
import '../directives/register.js'; import ts from 'typescript/lib/tsserverlibrary.js'; import { afterDeclarationsCompileComponentOptions } from '../transformer/after-declarations-component.js'; import { afterDeclarationsCompileDirectiveOptions } from '../transformer/after-declarations-directive.js'; import { beforeCompileComponentOptions } from '../transformer/before-component.js'; import { beforeCompileDirectiveOptions } from '../transformer/before-directive.js'; import { scanDirectivesTypeVisitor } from '../transformer/scan-directives.js'; import { dirname, join, resolve, relative } from 'path'; import { existsSync } from 'fs'; export function getTransformers(program) { return { before: [ beforeCompileDirectiveOptions(program), beforeCompileComponentOptions(program), ], after: [], afterDeclarations: [ afterDeclarationsCompileComponentOptions(program), afterDeclarationsCompileDirectiveOptions(program), ], }; } export function scanDirectives(program) { program.getSourceFiles().forEach(scanDirectivesTypeVisitor); } export function scanDirectivesOnceAsTransformer() { let scanDone = false; let ignoreTransformer = (context) => sourceFile => sourceFile; return (program) => { if (scanDone) { return ignoreTransformer; } scanDone = true; scanDirectives(program); return ignoreTransformer; }; } export function emitProgram(program) { scanDirectives(program); program.emit(undefined, undefined, undefined, undefined, getTransformers(program)); } export function compileFiles(files, options) { const host = ts.createCompilerHost(options); const program = ts.createProgram(files, options, host); emitProgram(program); } const formatHost = { getCanonicalFileName: path => path, getCurrentDirectory: ts.sys.getCurrentDirectory, getNewLine: () => ts.sys.newLine }; function reportDiagnostic(diagnostic) { console.error("Error", diagnostic.code, ":", ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())); } /** * Prints a diagnostic every time the watch status changes. * This is mainly for messages like "Starting compilation" or "Compilation completed". */ function reportWatchStatusChanged(diagnostic) { console.info(ts.formatDiagnostic(diagnostic, formatHost)); } export function compileAndWatchFiles(configPath, cmd) { const createProgram = ts.createSemanticDiagnosticsBuilderProgram; const host = ts.createWatchCompilerHost(configPath, cmd.options, ts.sys, createProgram, reportDiagnostic, reportWatchStatusChanged, cmd.watchOptions); const programFactory = ts.createWatchProgram(host); const programBuilder = programFactory.getProgram(); const program = programBuilder.getProgram(); emitProgram(program); } export function patchProgram(tsProgram) { const program = tsProgram; program.__emit = program.emit; const programTransformers = getTransformers(program); program.emit = (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => { if (!customTransformers) { return program.__emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, programTransformers); } return program.__emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, { before: [...(customTransformers?.before ?? []), ...programTransformers.before], after: [...(customTransformers?.after ?? []), ...programTransformers.after], afterDeclarations: [...(customTransformers?.afterDeclarations ?? []), ...programTransformers.afterDeclarations], }); }; } export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) { const program = ts.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); scanDirectives(program.getProgram()); patchProgram(program.getProgram()); return program; } const diagHost = { getCanonicalFileName: function (fileName) { return ts.sys.resolvePath(fileName); }, getCurrentDirectory: function () { return ts.sys.getCurrentDirectory(); }, getNewLine: function () { return ts.sys.newLine; } }; function getTime() { const date = new Date(); return `[${date.toLocaleTimeString('en-US')}]`; } function reportDiag(diag) { let output = ts.sys.writeOutputIsTTY?.() ? ts.formatDiagnosticsWithColorAndContext([diag], diagHost) : ts.formatDiagnostic(diag, diagHost); output = output.replace(/^[\r\n]+/, '').replace(/[\r\n]+$/, ''); ts.sys.write(`${getTime()} ${output}` + '\n'); } function reportError(errorCount, filesInError) { ts.sys.write(`Error count: ${errorCount}\n`); filesInError.forEach(error => ts.sys.write(`Error file: ${error?.fileName}(${error?.line})\n`)); } function printProjects(solution) { const projects = solution?.getBuildOrder(); if (Array.isArray(projects) && projects?.length) { console.log(`${getTime()} Projects in this build: `); projects.forEach(project => console.log(`\t* ${relative(process.cwd(), project)}`)); } } export function compileSolution(configFilePath, cmd) { const rootNames = [dirname(configFilePath)]; const solutionHost = ts.createSolutionBuilderHost(ts.sys, createEmitAndSemanticDiagnosticsBuilderProgram, reportDiag, reportDiag, reportError); const solution = ts.createSolutionBuilder(solutionHost, rootNames, {}); printProjects(solution); solution.build(); } export function compileSolutionAndWatch(configFilePath, cmd) { const rootNames = [dirname(configFilePath)]; const solutionHost = ts.createSolutionBuilderWithWatchHost(ts.sys, createEmitAndSemanticDiagnosticsBuilderProgram, reportDiag, reportDiag, reportDiag); const solution = ts.createSolutionBuilderWithWatch(solutionHost, rootNames, {}, cmd.watchOptions); printProjects(solution); solution.build(); } export function getConfigPath() { const args = process.argv.slice(2); let tsconfig = args.filter(arg => arg.includes('tsconfig'))[0]; if (!tsconfig && args.length > 1 /** -b */) { const path = join(args.at(-1), 'tsconfig.json'); if (existsSync(path)) { tsconfig = resolve(path); } } const configPath = ts.findConfigFile('./', /*searchPath*/ ts.sys.fileExists, tsconfig ?? 'tsconfig.json'); if (!configPath) { throw new Error("Could not find a valid 'tsconfig.json'."); } return configPath; } export function compileArgs() { const configPath = getConfigPath(); const cmd = ts.getParsedCommandLineOfConfigFile(configPath, {}, ts.sys); if (!cmd) { return; } if (cmd.projectReferences?.length) { compileSolution(configPath, cmd); } else { compileFiles(cmd.fileNames, cmd.options); } } export function compileAndWatchArgs() { const configPath = getConfigPath(); const cmd = ts.getParsedCommandLineOfConfigFile(configPath, {}, ts.sys); if (!cmd) { return; } if (cmd.projectReferences?.length) { compileSolutionAndWatch(configPath, cmd); } else { compileAndWatchFiles(configPath, cmd); } } //# sourceMappingURL=compiler.js.map