Как я могу использовать API компилятора TS, чтобы найти, где переменная была определена в другом файле - PullRequest
4 голосов
/ 21 января 2020

учитывая:

// foo.ts
import { bar } from "./bar"

// bar.ts
export const bar = 3;

Если у меня есть ts.Symbol для bar в "foo.ts", как я могу получить bar в "bar.ts"?

В идеале API компилятора TS должен представлять цепочку использования-определения, которую я могу пройти, чтобы найти определение. Я не думаю, что это так.

Так что теперь я пытаюсь:

  • использовать спецификатор модуля "./bar.ts" и текущий ts.SourceFile чтобы получить ts.ResolvedModule объект, представляющий "bar.ts", который содержит полный путь к файлу.
  • Do ts.SourceFile(fullFilePath) чтобы получить ts.SourceFile для "bar.ts"
  • Do checker.getExportsOfModule(symbolForBarDotTs), чтобы получить экспорт из "bar.ts" и найти файл с подходящим именем.

Сложная часть, похоже, разрешает модуль из спецификатора модуля. Я не хочу писать logi c для разрешения модулей с нуля, потому что алгоритм сложен и зависит от взаимодействия как минимум шести опций компилятора. Две части API компилятора TS казались многообещающими:

  • host.resolveModuleNames, который, к сожалению, доступен только в том случае, если хост реализовал его, а хост компилятора по умолчанию не реализует его.
  • используйте (program.getSourceFile(pathToFoo) as any).resolvedModules. Свойство resolvedModules, кажется, имеет именно то, что я ищу, но не является частью API publi c.

Есть ли лучший способ? Я надеюсь:

  • прекратить использование не закрытого API
  • прекратить делать так много работы, что компилятор уже знает, как это сделать

    " bar.ts "

В этом случае легко увидеть, что" ./bar "относится к смежному исходному файлу в файловой системе с соответствующим именем, но когда кто-то использует "paths" или "node_modules" или "@types", et c. тогда разрешение модуля нетривиально.

Обновление

По общему вопросу:

Если у меня есть ts.Symbol для bar in " foo.ts ", как мне добраться до bar в" bar.ts "?

@ Ответ DavidSherret будет работать большую часть времени.

Однако он не выполняет то, что мне нужно, в следующем случае:

// foo.ts
import { bar } from "./bar"

// bar.ts
export { bar } from "./baz"

// baz.ts
export const bar = 3;

TypeChecker # getAliasedSymbol говорит, что baz в "foo.ts" указывает на bar в " baz.ts ", пропуская" bar.ts "целиком. Это не сработало для моих целей, потому что я пытаюсь выяснить, учитывая набор точек входа, какие части файлов .d.ts больше не нужны, и удалить ненужные части. В этом случае было бы плохой идеей удалить "bar.ts".

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Символ именованного импорта будет иметь связанный «псевдоним», который представляет объявление. Таким образом, чтобы получить символ объявления переменной, вы можете использовать метод TypeChecker#getAliasedSymbol, а затем получить объявление.

Например:

const barNamedImportSymbol = typeChecker.getSymbolAtLocation(barNamedImport.name)!;
const barSymbol = typeChecker.getAliasedSymbol(barNamedImportSymbol);
const barDeclaration = barSymbol.declarations[0] as ts.VariableDeclaration;

console.log(barDeclaration.getText(barFile)); // outputs `bar = 3`

Именованная импортная декларация импорта имеет отдельный символ потому что это символ, указывающий c на файл "foo.ts".

Обновление: получение символа файла, указанного в спецификаторе модуля

Чтобы получить символ файл, указанный в спецификаторе модуля объявлений импорта или экспорта, вы можете получить символ узла спецификатора модуля:

const otherFileSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier)!;

Оттуда вы можете проверить его экспорт на определенное имя:

const barSymbol = otherFileSymbol.exports!.get(ts.escapeLeadingUnderscores("bar"))!;
// outputs: export { bar } from "./baz"; in second example above
console.log(barSymbol.declarations[0].parent.parent.getText());
0 голосов
/ 22 января 2020

Для разрешения имен модулей используйте ts.resolveModuleName, , как рекомендовано для этой проблемы TS .

Вот подпись от typescript.d.ts:

resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];

В качестве альтернативы, чтобы перейти непосредственно к исходному определению символа, см. @ ответ DavidSherret

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