ts-simple-ast
Version:
TypeScript compiler wrapper for AST navigation and code generation.
180 lines (178 loc) • 6.99 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const minimatch_1 = require("minimatch");
const errors = require("./errors");
const utils_1 = require("./utils");
const DefaultFileSystemHost_1 = require("./DefaultFileSystemHost");
const GlobalContainer_1 = require("./GlobalContainer");
/**
* Compiler wrapper.
*/
class TsSimpleAst {
/**
* Initializes a new instance.
* @param options - Optional options.
* @param fileSystem - Optional file system host. Useful for mocking access to the file system.
*/
constructor(options = {}, fileSystem = new DefaultFileSystemHost_1.DefaultFileSystemHost()) {
this.fileSystem = fileSystem;
this.global = new GlobalContainer_1.GlobalContainer(fileSystem, getCompilerOptionsFromOptions(options, fileSystem), true);
if (options.manipulationSettings != null)
this.global.manipulationSettings.set(options.manipulationSettings);
}
/** Gets the manipulation settings. */
get manipulationSettings() {
return this.global.manipulationSettings;
}
/**
* Add source files based on file globs.
* @param fileGlobs - File globs to add files based on.
*/
addSourceFiles(...fileGlobs) {
const filePaths = this.fileSystem.glob(fileGlobs);
for (const filePath of filePaths) {
// ignore any FileNotFoundErrors
try {
this.getOrAddSourceFile(filePath);
}
catch (ex) {
/* istanbul ignore if */
if (!(ex instanceof errors.FileNotFoundError))
throw ex;
}
}
}
/**
* Gets or adds a source file from a file path.
* @param filePath - File path to create the file from.
*/
getOrAddSourceFile(filePath) {
const absoluteFilePath = utils_1.FileUtils.getStandardizedAbsolutePath(filePath);
if (!this.fileSystem.fileExistsSync(absoluteFilePath))
throw new errors.FileNotFoundError(absoluteFilePath);
return this.global.compilerFactory.getSourceFileFromFilePath(absoluteFilePath);
}
/**
* Adds a source file from text.
* @param filePath - File path for the source file.
* @param sourceFileText - Source file text.
* @throws - InvalidOperationError if a source file already exists at the provided file path.
*/
addSourceFileFromText(filePath, sourceFileText) {
return this.global.compilerFactory.addSourceFileFromText(filePath, sourceFileText);
}
/**
* Adds a source file from a structure.
* @param filePath - File path for the source file.
* @param structure - Structure that represents the source file.
* @throws - InvalidOperationError if a source file already exists at the provided file path.
*/
addSourceFileFromStructure(filePath, structure) {
const sourceFile = this.global.compilerFactory.addSourceFileFromText(filePath, "");
sourceFile.fill(structure);
return sourceFile;
}
/**
* Removes a source file from the AST.
* @param sourceFile - Source file to remove.
* @returns True if removed.
*/
removeSourceFile(sourceFile) {
return this.global.languageService.removeSourceFile(sourceFile);
}
getSourceFileOrThrow(fileNameOrSearchFunction) {
const sourceFile = this.getSourceFile(fileNameOrSearchFunction);
if (sourceFile == null) {
if (typeof fileNameOrSearchFunction === "string")
throw new errors.InvalidOperationError(`Could not find source file based on the provided name or path: ${fileNameOrSearchFunction}.`);
else
throw new errors.InvalidOperationError(`Could not find source file based on the provided condition.`);
}
return sourceFile;
}
getSourceFile(fileNameOrSearchFunction) {
let searchFunction = fileNameOrSearchFunction;
if (typeof fileNameOrSearchFunction === "string")
searchFunction = def => utils_1.FileUtils.filePathMatches(def.getFilePath(), fileNameOrSearchFunction);
return this.getSourceFiles().find(searchFunction);
}
/**
* Gets all the source files contained in the compiler wrapper.
* @param globPattern - Glob pattern for filtering out the source files.
*/
getSourceFiles(globPattern) {
let sourceFiles = this.global.languageService.getSourceFiles();
if (typeof globPattern === "string") {
const mm = new minimatch_1.Minimatch(globPattern, { matchBase: true });
sourceFiles = sourceFiles.filter(s => mm.match(s.getFilePath()));
}
return sourceFiles;
}
/**
* Saves all the unsaved source files.
*/
saveUnsavedSourceFiles() {
return Promise.all(this.getUnsavedSourceFiles().map(f => f.save()));
}
/**
* Saves all the unsaved source files synchronously.
*
* Remarks: This might be very slow compared to the asynchronous version if there are a lot of files.
*/
saveUnsavedSourceFilesSync() {
// sidenote: I wish I could do something like in c# where I do this all asynchronously then
// wait synchronously on the task. It would not be as bad as this is performance wise. Maybe there
// is a way, but people just shouldn't be using this method unless they're really lazy.
for (const file of this.getUnsavedSourceFiles())
file.saveSync();
}
getUnsavedSourceFiles() {
return this.getSourceFiles().filter(f => !f.isSaved());
}
/**
* Gets the compiler diagnostics.
*/
getDiagnostics() {
// todo: implement cancellation token
const compilerDiagnostics = ts.getPreEmitDiagnostics(this.global.program.compilerObject);
return compilerDiagnostics.map(d => this.global.compilerFactory.getDiagnostic(d));
}
/**
* Gets the language service.
*/
getLanguageService() {
return this.global.languageService;
}
/**
* Gets the program.
*/
getProgram() {
return this.global.program;
}
/**
* Gets the type checker.
*/
getTypeChecker() {
return this.global.typeChecker;
}
/**
* Emits all the source files.
* @param emitOptions - Optional emit options.
*/
emit(emitOptions = {}) {
return this.global.program.emit(emitOptions);
}
/**
* Gets the compiler options.
*/
getCompilerOptions() {
// return a copy
return Object.assign({}, this.global.compilerOptions);
}
}
exports.TsSimpleAst = TsSimpleAst;
function getCompilerOptionsFromOptions(options, fileSystem) {
return Object.assign({}, (options.tsConfigFilePath == null ? {} : utils_1.getCompilerOptionsFromTsConfig(options.tsConfigFilePath, fileSystem)), (options.compilerOptions || {}));
}
//# sourceMappingURL=TsSimpleAst.js.map