Skip to content

Instantly share code, notes, and snippets.

@Glavin001
Last active March 5, 2022 07:07
Show Gist options
  • Save Glavin001/6281f12ee97f40fb8fbde5a319457119 to your computer and use it in GitHub Desktop.
Save Glavin001/6281f12ee97f40fb8fbde5a319457119 to your computer and use it in GitHub Desktop.
How to list all explicit exports from TypeScript file with TypeScript Compiler/AST

Install ts-node with Node.js v13+ then you can run:

./node_modules/.bin/ts-node -O '{"module":"commonjs"}' list-exports.ts <files...>

The -O '{"module":"commonjs"}' part is to allow using import & export statements: TypeStrong/ts-node#922 (comment)

Demo

Running the script on example.ts:

./node_modules/.bin/ts-node -O '{"module":"commonjs"}' list-exports.ts ./example.ts

Will print the following:

File names: ./example.ts
export specifier something
export specifier alias
export var blah
export var a
export var b
export function testing
export specifier testing2
export function MyInterface
export function MyType
[
  'something', 'alias',
  'blah',      'a',
  'b',         'testing',
  'testing2',  'MyInterface',
  'MyType'
]

The array printed at the end is a list of exported names/identifiers. Check it against what you would expect from example.ts.

How to add more support for missing export cases

There may be missing cases. No problem!

  1. Use https://astexplorer.net/ !
  2. Change the parser to typescript.
  3. Enter your code in the left editor panel
  4. Preview the AST on the right panel
  5. Edit the list-exports.ts to catch the case you want and then add new identifiers/names to allExports array.
export * from './test'
export { something, some as alias } from './else';
export * from './test2';
export const blah = 'test';
export const a, b;
export function testing() {
}
export { testing as testing2 }
export interface MyInterface {
}
export type MyType = string;
import { readFileSync } from "fs";
import * as ts from "typescript";
export function getExportsForSourceFile(sourceFile: ts.SourceFile) {
const allExports: string[] = [];
visitNode(sourceFile);
function visitNode(node: ts.Node) {
if (ts.isExportSpecifier(node)) {
const name = node.name.getText();
console.log('export specifier', name);
allExports.push(name);
} else if (node.kind === ts.SyntaxKind.ExportKeyword) {
const parent = node.parent;
if (ts.isFunctionDeclaration(parent) || ts.isTypeAliasDeclaration(parent) || ts.isInterfaceDeclaration(parent)) {
const name = parent.name.getText();
console.log('export function', name);
allExports.push(name);
} else if (ts.isVariableStatement(parent)) {
parent.declarationList.declarations.forEach(declaration => {
const name = declaration.name.getText();
console.log('export var', name);
allExports.push(name);
});
}
}
ts.forEachChild(node, visitNode);
}
return allExports;
}
const fileNames = process.argv.slice(2);
console.log(`File names: ${fileNames}`);
fileNames.forEach(fileName => {
// Parse a file
const sourceFile = ts.createSourceFile(
fileName,
readFileSync(fileName).toString(),
ts.ScriptTarget.ES2015,
/*setParentNodes */ true
);
const allExports = getExportsForSourceFile(sourceFile);
console.log(allExports);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment