UNPKG

budgie-cli

Version:
143 lines (121 loc) 4.93 kB
import { EOL } from "os"; import { createTransformer, ITransformationResults, Transformer } from "ts-budgie"; import * as ts from "typescript"; import { replaceFileExtension } from "../../utils/extensions"; import { defaultValue } from "../../utils/values"; import { budgieExtension } from "../budgieConverter"; import { ConversionStatus, IConversionResult, IConverter, ICreateConverterDependencies } from "../converter"; import { IUnsupportedComplaint } from "./collectedUnsupportedTransforms"; export interface ITsconfigOptions { compilerOptions: ts.CompilerOptions; exclude?: ReadonlyArray<string>; files?: ReadonlyArray<string>; include: ReadonlyArray<string>; } /** * Extension for TypeScript files. */ export const tsExtension = ".ts"; /** * Dependencies to initialize a new instance of the TypeScriptConverter class. */ export interface ITypeScriptConverterDependencies extends ICreateConverterDependencies { /** * Options for the TypeScript compiler. */ tsconfigOptions: ITsconfigOptions; } /** * Creates TS source files for each file name. * * @param existingFileContents Writable cache of contents of file paths, keyed by unique file name. * @param scriptTarget Specified TypeScript language output target. * @returns TypeScript source files, keyed by unique file path. */ const createSourceFilesMap = (existingFileContents: Map<string, string>, scriptTarget: ts.ScriptTarget): Map<string, ts.SourceFile> => { const map = new Map<string, ts.SourceFile>(); existingFileContents.forEach((fileContents: string, fileName: string) => { map.set(fileName, ts.createSourceFile(fileName, fileContents, scriptTarget, true, ts.ScriptKind.TS)); }); return map; }; /** * @todo Use this once ts-budgie supports emitting a summary of unsupported syntax. */ export const complainForTransformation = (sourceFile: ts.SourceFile, complaint: IUnsupportedComplaint) => { const { text } = sourceFile; const { start } = complaint.range; const line = text.substring(0, start).split(/\r\n|\r|\n/g).length; return `Line ${line + 1}: Unsupported syntax: ${complaint.line.args[0]}`; }; /** * Converts TypeScript files to their Budgie outputs. */ export class TypeScriptConverter implements IConverter { /** * Dependencies used for initialization. */ private readonly dependencies: ITypeScriptConverterDependencies; /** * TypeScript source files, keyed by unique file path. */ private readonly sourceFiles: Map<string, ts.SourceFile>; /** * Transforms TypeScript to Budgie. */ private readonly transformer: Transformer; /** * Initializes a new instance of the TypeScriptConverter class. * * @param dependencies Dependencies used for initialization. * @param options Options for converting files. */ public constructor(dependencies: ITypeScriptConverterDependencies) { this.dependencies = dependencies; this.sourceFiles = createSourceFilesMap( dependencies.existingFileContents, defaultValue(dependencies.tsconfigOptions.compilerOptions.target, () => ts.ScriptTarget.Latest), ); this.transformer = createTransformer({ baseDirectory: dependencies.baseDirectory, outputNamespace: dependencies.outputNamespace, sourceFiles: Array.from(this.sourceFiles.values()), }); } /** * Converts a TypeScript file to its Budgie output. * * @param sourcePath Original Budgie file path. * @returns The file's Budgie output. */ public async convertFile(sourcePath: string): Promise<IConversionResult> { if (this.dependencies.metadata !== undefined && sourcePath === "src/index.ts") { return { sourcePath, status: ConversionStatus.Succeeded, }; } const sourceFile = this.sourceFiles.get(sourcePath); if (sourceFile === undefined) { throw new Error(`Unknown source file: '${sourcePath}'.`); } const outputPath = replaceFileExtension(sourcePath, tsExtension, budgieExtension); let transformationResults: ITransformationResults; try { transformationResults = this.transformer.transformSourceFile(sourceFile); } catch (error) { return { error, outputPath, sourcePath, status: ConversionStatus.Failed, }; } await this.dependencies.fileSystem.writeFile(outputPath, transformationResults.printed.join(EOL)); return { outputPath, sourcePath, status: ConversionStatus.Succeeded, }; } }