Создание SourceFile из массива Statement-узлов вместо строки - PullRequest
1 голос
/ 14 апреля 2020

Легко создать SoureFile объект из простой строки:

ts.createSourceFile(fileName, sourceText, languageVersion, setParentNodes, scriptKind)

Однако я не вижу способа создать объект из массива Statement -узлов (созданных различные фабричные функции).

Я пытался найти решение, подобное этому:

const source = ts.createSourceFile(fileName, '', languageVersion);
source.statements = myNodeArray;

Но это (возможно, неудивительно) не работает. Я также попытался (ab) использовать API-интерфейс преобразователя следующим образом:

function createSourcefile(filename: string, ast: ts.Node[], languageVersion: ts.ScriptTarget): ts.SourceFile {
    const dummy = ts.createSourceFile(filename, 'dummy', languageVersion); // need at least 1 node

    return ts.transform(
        dummy,
        [ transformContext => sourceFile => ts.visitEachChild(sourceFile, node => ast, transformContext) ]
    ).transformed[0];
}

Но, похоже, это тоже не работает.

При обоих методах я получаю следующую ошибку во время emit process:

Error: start < 0
  at createTextSpan (node_modules\typescript\lib\typescript.js:10263:19)
  at Object.createTextSpanFromBounds (node_modules\typescript\lib\typescript.js:10272:16)
  at getErrorSpanForNode (node_modules\typescript\lib\typescript.js:13544:19)
  at createDiagnosticForNodeInSourceFile (node_modules\typescript\lib\typescript.js:13449:20)
  at Object.createDiagnosticForNode (node_modules\typescript\lib\typescript.js:13440:16)
  at lookupOrIssueError (node_modules\typescript\lib\typescript.js:34976:22)
  at addDuplicateDeclarationError (node_modules\typescript\lib\typescript.js:35177:23)
  at \node_modules\typescript\lib\typescript.js:35173:17
  at Object.forEach (node_modules\typescript\lib\typescript.js:317:30)
  at addDuplicateDeclarationErrorsForSymbols (node_modules\typescript\lib\typescript.js:35171:16)
  at mergeSymbol (node_modules\typescript\lib\typescript.js:35158:21)
  at \node_modules\typescript\lib\typescript.js:35200:47
  at Map.forEach (<anonymous>)
  at mergeSymbolTable (node_modules\typescript\lib\typescript.js:35198:20)
  at initializeTypeChecker (node_modules\typescript\lib\typescript.js:66463:21)
  at Object.createTypeChecker (node_modules\typescript\lib\typescript.js:34935:9)
  at getDiagnosticsProducingTypeChecker (node_modules\typescript\lib\typescript.js:98560:93)
  at emitWorker (node_modules\typescript\lib\typescript.js:98588:32)
  at \node_modules\typescript\lib\typescript.js:98569:66
  at runWithCancellationToken (node_modules\typescript\lib\typescript.js:98665:24)
  at Object.emit (node_modules\typescript\lib\typescript.js:98569:20)
  *snip*

Есть ли способ заставить это работать?

Полагаю, я теоретически мог бы использовать принтер для преобразования AST в строку , но это, очевидно, было бы огромной тратой.


Я сделал gist с автономным примером с использованием "виртуального хоста компилятора" и предложение Дэвида Шеррета по удалению диапазона.

Как ни странно, я обнаружил, что эта ошибка возникает не для всех типов узлов. В моем (ограниченном) тестировании я столкнулся с этим, только когда AST содержал ImportDeclaration узел.

1 Ответ

1 голос
/ 14 апреля 2020

Спасибо за воспроизводимый пример! Я полностью изменил свой ответ, поэтому просмотрите историю моего прошлого ответа.

Я посмотрел на это, и происходит следующее:

  1. Проверка типов идет для проверки файла .
  2. Встречается диагностика c "Cannot find module 'bar'." (Примечание: это после исправления ts.createImportDeclaration для предоставления строкового литерала, а не идентификатора для спецификатора модуля)
  3. Идет в создайте диапазон для этой диагностики c и выбросы функции createTextSpan, потому что синтетические узлы c имеют позицию меньше нуля. Это независимо от моего предыдущего предложения stripRanges, поскольку ts.createImportDeclaration создает узел с отрицательными позициями.

Так что после выполнения этого исследования мне напомнили, что средство проверки типов часто делает предположение, что узлы будут ссылаться на позиции в тексте исходного файла. Это потому, что фаза преобразования компиляции происходит после проверки типа.

Если вы хотите проверить тип в созданном вами исходном файле, я думаю, вам нужно будет распечатать его в строку и выполнить повторный анализ, чтобы получить новый исходный файл. содержащий нисходящие узлы с правильными позициями, затем используйте это.

Если вам не нужна проверка типов, то, к сожалению, на данный момент я не думаю, что есть способ преобразовать код без проверки типов с использованием текущего API , Может быть возможно взломать что-нибудь в пользовательских преобразователях при их выдаче, хотя ... возможно, иметь пустой файл, а затем добавить операторы во время пользовательского преобразования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...