Skip to content

Instantly share code, notes, and snippets.

@hipstersmoothie
Last active April 24, 2020 17:47
Show Gist options
  • Save hipstersmoothie/1a3f5d068d31c8057c85a211944cc650 to your computer and use it in GitHub Desktop.
Save hipstersmoothie/1a3f5d068d31c8057c85a211944cc650 to your computer and use it in GitHub Desktop.
const ts = require("typescript");
const vfs = require("@typescript/vfs");
const compilerOptions = {
strict: true,
target: ts.ScriptTarget.ES2015,
typeRoots: [],
lib: ["es5"],
skipDefaultLibCheck: true,
skipLibCheck: true,
moduleResolution: ts.ModuleResolutionKind.NodeJs,
module: ts.ModuleKind.ES2015,
};
const filename = "index.ts";
const file = `
interface StackBaseProps<T> {
as: T;
hasWrap?: boolean;
}
interface StackJustifyProps {
/** The foo prop should not repeat the description */
foo?: 'blue';
/** You cannot use gap when using a "space" justify property */
gap?: never;
}
interface StackGapProps {
/** The foo prop should not repeat the description */
foo?: 'red';
/** The space between children */
gap?: number;
}
type StackProps<T = string> = StackBaseProps<T> & (StackGapProps | StackJustifyProps);
`;
async function run() {
const fsMap = await vfs.createDefaultMapFromNodeModules(compilerOptions);
fsMap.set(filename, file);
const system = vfs.createSystem(fsMap);
const host = vfs.createVirtualCompilerHost(system, compilerOptions, ts);
const program = ts.createProgram({
rootNames: [...fsMap.keys()],
options: compilerOptions,
host: host.compilerHost,
});
const checker = program.getTypeChecker();
// This will update the fsMap with new files
// for the .d.ts and .js files
program.emit();
// Now I can look at the AST for the .ts file too
const index = program.getSourceFile("index.ts");
const properties = checker
.getDeclaredTypeOfSymbol(index.locals.get("StackProps"))
.getProperties();
console.log(
properties.map((prop) => {
const propType = checker.getTypeOfSymbolAtLocation(prop, index);
const isOptional = (prop.getFlags() & ts.SymbolFlags.Optional) !== 0;
const description = Array.from(
new Set(
prop
.getDocumentationComment()
.map((d) => d.text.trim())
.filter((t) => t !== "")
)
).join("\n");
return {
name: prop.getName(),
type: checker.typeToString(propType),
// BUG: Required always returns true
required: !isOptional,
description,
};
})
);
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment