in modules/material-parser/src/parse/ts/index.ts [479:609]
export default function parseTS(filePath: string, args: IParseArgs): ComponentDoc[] {
if (!filePath) return [];
let basePath = args.moduleDir || args.workDir || path.dirname(filePath);
let tsConfigPath = findConfig('tsconfig.json', { cwd: basePath }); // path.resolve(basePath, 'tsconfig.json')
if (
!tsConfigPath ||
!existsSync(tsConfigPath) ||
(args.accesser === 'online' && tsConfigPath === 'tsconfig.json')
) {
tsConfigPath = defaultTsConfigPath;
} else {
basePath = path.dirname(tsConfigPath);
}
log('ts config path is', tsConfigPath);
const { config, error } = ts.readConfigFile(tsConfigPath, (filename) =>
readFileSync(filename, 'utf8'));
if (error !== undefined) {
const errorText = `Cannot load custom tsconfig.json from provided path: ${tsConfigPath}, with error code: ${error.code}, message: ${error.messageText}`;
throw new Error(errorText);
}
const { options, errors } = ts.parseJsonConfigFileContent(
config,
ts.sys,
basePath,
{},
tsConfigPath,
);
if (errors && errors.length) {
throw errors[0];
}
log('ts config is', options);
// const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths];
generateDTS(args);
const program = ts.createProgram([filePath], options);
const parser = new MyParser(program, {});
const checker = program.getTypeChecker();
const result = [filePath]
.map((fPath) => program.getSourceFile(fPath))
.filter((sourceFile) => typeof sourceFile !== 'undefined')
.reduce((docs: any[], sourceFile) => {
const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node);
if (!moduleSymbol) {
return docs;
}
const exportSymbols = checker.getExportsOfModule(moduleSymbol);
for (let index = 0; index < exportSymbols.length; index++) {
const sym: SymbolWithMeta = exportSymbols[index];
const name = sym.getName();
if (blacklistNames.includes(name)) {
continue;
}
// polyfill valueDeclaration
sym.valueDeclaration =
sym.valueDeclaration || (Array.isArray(sym.declarations) && sym.declarations[0]);
if (!sym.valueDeclaration) {
continue;
}
const info = parser.getComponentInfo(sym, sourceFile);
if (info === null) {
continue;
}
const exportName = sym.meta && sym.meta.exportName;
const meta = {
subName: exportName ? name : '',
exportName: exportName || name,
};
if (docs.find((x) => isEqual(x.meta, meta))) {
continue;
}
docs.push({
...info,
meta,
});
// find sub components
if (!!sym.declarations && sym.declarations.length === 0) {
continue;
}
const type = checker.getTypeOfSymbolAtLocation(
sym,
sym.valueDeclaration || sym.declarations[0],
);
Array.prototype.push.apply(
exportSymbols,
type.getProperties().map((x: SymbolWithMeta) => {
x.meta = { exportName: name };
return x;
}),
);
}
return docs;
}, []);
const coms = result.reduce((res: any[], info: any) => {
if (!info || !info.props || isEmpty(info.props)) return res;
const props = Object.keys(info.props).reduce((acc: any[], name) => {
// omit aria related properties temporarily
if (name.startsWith('aria-')) {
return acc;
}
try {
const item: any = transformItem(name, info.props[name]);
acc.push(item);
} catch (e) {
log(e);
}
return acc;
}, []);
const exportName = info?.meta?.exportName;
res.push({
componentName: getComponentName(exportName, info.displayName),
props,
meta: info.meta || {},
});
return res;
}, []);
return coms;
}