UNPKG

typeorm-codebase-sync

Version:

Automatically update your codebase to add migrations, entities and subscribers to your `data-source.ts` file

119 lines 5.56 kB
import fs from "fs"; import path from "path"; import ts from "typescript"; import { determineModuleSystemForFile } from "./moduleSystem.js"; import { replaceCodeBlankLinesWithComments } from "./replaceCodeBlankLinesWithComments.js"; import { getRelativeImportPath as getRelativeImportPathUtil } from "./getRelativeImportPath.js"; export class Codebase { constructor({ entryFilePath, moduleSystem }) { this.sourceFiles = new Map(); this.updatedSourceFilePaths = new Set(); this.transformedFilesMap = new Map(); this.entryFilePath = entryFilePath; if (moduleSystem != null) this.moduleSystem = moduleSystem; const tsconfigPath = ts.findConfigFile(entryFilePath, ts.sys.fileExists); const tsconfig = tsconfigPath != null ? ts.readJsonConfigFile(tsconfigPath, ts.sys.readFile) : {}; this.host = ts.createCompilerHost(tsconfig, false); this._addHostReadFileMiddleware(); this.program = ts.createProgram([this.entryFilePath], tsconfig, this.host); this.checker = this.program.getTypeChecker(); } async initialize() { if (this.initializePromise == null) this.initializePromise = (async () => { if (this.moduleSystem == null) this.moduleSystem = await determineModuleSystemForFile(this.entryFilePath); })(); await this.initializePromise; return this; } getSourceFile(filePath) { const absoluteFilePath = path.resolve(filePath); let sourceFile = this.sourceFiles.get(absoluteFilePath); if (sourceFile == null) { sourceFile = this.program.getSourceFile(absoluteFilePath); if (sourceFile != null) this.sourceFiles.set(absoluteFilePath, sourceFile); } return sourceFile; } updateSourceFile(sourceFile) { const absoluteFilePath = path.resolve(sourceFile.fileName); this.sourceFiles.set(absoluteFilePath, sourceFile); return sourceFile; } markSourceFileAsUpdated(sourceFile) { const filePath = path.resolve(sourceFile.fileName); this.updatedSourceFilePaths.add(filePath); const knownSourceFile = this.getSourceFile(filePath); if (knownSourceFile == null) this.sourceFiles.set(filePath, sourceFile); return sourceFile; } getModifiedSourceFiles() { const res = []; for (const filePath of this.updatedSourceFilePaths) { const sourceFile = this.getSourceFile(filePath); if (sourceFile != null) res.push(sourceFile); } return res; } getRelativeImportPath(containingFilePath, importedFilePath) { return getRelativeImportPathUtil(containingFilePath, importedFilePath, this.moduleSystem); } writeChangesToFilesystem() { const writtenFilePaths = []; const pendingFileWrites = []; this.getSourceFile(this.entryFilePath); const transformedEntryFile = this.transformedFilesMap.get(path.resolve(this.entryFilePath)); const entryFileUsesCrlf = transformedEntryFile?.content.includes("\r\n") ?? false; for (const filePath of this.updatedSourceFilePaths) { const sourceFile = this.getSourceFile(filePath); if (sourceFile == null) return []; const transformedFile = this.transformedFilesMap.get(filePath); const printer = ts.createPrinter({ newLine: transformedFile == null ? (entryFileUsesCrlf ? ts.NewLineKind.CarriageReturnLineFeed : ts.NewLineKind.LineFeed) : (transformedFile.content.includes("\r\n") ? ts.NewLineKind.CarriageReturnLineFeed : ts.NewLineKind.LineFeed), removeComments: false }); const printFile = ts.createSourceFile(path.basename(filePath), "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); const compiledFileContent = printer.printNode(ts.EmitHint.Unspecified, sourceFile, printFile); let resultFileContent = compiledFileContent; if (transformedFile != null) { resultFileContent = compiledFileContent .split(transformedFile.comment) .join(""); // remove blank-line-preserving comments } pendingFileWrites.push({ filePath, content: resultFileContent }); } for (const { filePath, content } of pendingFileWrites) { fs.writeFileSync(filePath, content, "utf8"); writtenFilePaths.push(filePath); } return writtenFilePaths; } _addHostReadFileMiddleware() { const originalHostReadFile = this.host.readFile; this.host.readFile = (fileName) => { const absoluteFilePath = path.resolve(fileName); const extName = path.extname(absoluteFilePath); if (/^\.[cm]?[jt]s$/.test(extName)) { // this is needed in order to preserve blank lines after generating the new file from the AST const transformedFile = replaceCodeBlankLinesWithComments(fs.readFileSync(absoluteFilePath, "utf8")); this.transformedFilesMap.set(absoluteFilePath, transformedFile); return transformedFile.content; } return originalHostReadFile.call(this.host, fileName); }; } } //# sourceMappingURL=Codebase.js.map