Ситуация 1 - Использование только памяти - Нет доступа к файловой системе (например, в Интернете)
Это непростая задача, которая может занять некоторое время.Возможно, есть более простой способ, но я еще не нашел.
- Реализация
ts.CompilerHost
, где такие методы, как fileExists
, readFile
, directoryExists
, getDirectories()
и т. Д.. читать из памяти вместо фактической файловой системы. - Загрузить соответствующие lib файлы в вашу файловую систему в памяти в зависимости от того, что вам нужно (например, lib.es6.d.ts или lib.dom.d.ts ).
- Добавьте также файл в памяти в файловую систему в памяти.
- Создатьзапрограммируйте (используя
ts.createProgram
) и передайте пользовательский ts.CompilerHost
. - . Вызовите
ts.getPreEmitDiagnostics(program)
, чтобы получить диагностику.
Несовершенный пример
Вот краткий несовершенный пример, который неправильно реализует файловую систему в памяти и не загружает файлы lib (поэтому будут глобальные диагностические ошибки ... они могут быть проигнорированы или вы можете вызывать определенные методы на program
кроме program.getGlobalDiagnostics()
. Обратите внимание на поведение ts.getPreEmitDiagnostics
здесь ):
import * as ts from "typescript";
console.log(getDiagnosticsForText("const t: number = '';").map(d => d.messageText));
function getDiagnosticsForText(text: string) {
const dummyFilePath = "/file.ts";
const textAst = ts.createSourceFile(dummyFilePath, text, ts.ScriptTarget.Latest);
const options: ts.CompilerOptions = {};
const host: ts.CompilerHost = {
fileExists: filePath => filePath === dummyFilePath,
directoryExists: dirPath => dirPath === "/",
getCurrentDirectory: () => "/",
getDirectories: () => [],
getCanonicalFileName: fileName => fileName,
getNewLine: () => "\n",
getDefaultLibFileName: () => "",
getSourceFile: filePath => filePath === dummyFilePath ? textAst : undefined,
readFile: filePath => filePath === dummyFilePath ? text : undefined,
useCaseSensitiveFileNames: () => true,
writeFile: () => {}
};
const program = ts.createProgram({
options,
rootNames: [dummyFilePath],
host
});
return ts.getPreEmitDiagnostics(program);
}
Ситуация 2 - доступ к файлу system
Если у вас есть доступ к файловой системе, это намного проще, и вы можете использовать функцию, аналогичную приведенной ниже:
import * as path from "path";
function getDiagnosticsForText(
rootDir: string,
text: string,
options?: ts.CompilerOptions,
cancellationToken?: ts.CancellationToken
) {
options = options || ts.getDefaultCompilerOptions();
const inMemoryFilePath = path.resolve(path.join(rootDir, "__dummy-file.ts"));
const textAst = ts.createSourceFile(inMemoryFilePath, text, options.target || ts.ScriptTarget.Latest);
const host = ts.createCompilerHost(options, true);
overrideIfInMemoryFile("getSourceFile", textAst);
overrideIfInMemoryFile("readFile", text);
overrideIfInMemoryFile("fileExists", true);
const program = ts.createProgram({
options,
rootNames: [inMemoryFilePath],
host
});
return ts.getPreEmitDiagnostics(program, textAst, cancellationToken);
function overrideIfInMemoryFile(methodName: keyof ts.CompilerHost, inMemoryValue: any) {
const originalMethod = host[methodName] as Function;
host[methodName] = (...args: unknown[]) => {
// resolve the path because typescript will normalize it
// to forward slashes on windows
const filePath = path.resolve(args[0] as string);
if (filePath === inMemoryFilePath)
return inMemoryValue;
return originalMethod.apply(host, args);
};
}
}
// example...
console.log(getDiagnosticsForText(
__dirname,
"import * as ts from 'typescript';\n const t: string = ts.createProgram;"
));
При этом компиляторнайдите в указанной rootDir
папке node_modules
и используйте набранные там символы (их не нужно загружать в память каким-либо другим способом).