@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
239 lines • 9.95 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils");
const lodash_1 = __importDefault(require("lodash"));
const tsutils = __importStar(require("tsutils"));
const ts = __importStar(require("typescript"));
const serializeSymbol = (options) => {
const { checker, symbol } = options;
const doc = {
name: symbol.getName(),
documentation: ts.displayPartsToString(symbol.getDocumentationComment(checker)),
};
if (symbol.valueDeclaration) {
doc.type = checker.typeToString(checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration));
}
return doc;
};
const serializeSignature = (options) => {
const { checker, signature } = options;
return {
parameters: signature.parameters.map((p) => serializeSymbol({ symbol: p, checker })),
returnType: checker.typeToString(signature.getReturnType()),
documentation: ts.displayPartsToString(signature.getDocumentationComment(checker)),
};
};
const introspectionUtil = {
introspect(tsFiles) {
const filePaths = tsFiles;
const program = ts.createProgram(filePaths, {});
const checker = program.getTypeChecker();
// for building results
const introspects = [];
for (const tsFile of filePaths) {
const sourceFile = program.getSourceFile(tsFile);
const results = { classes: [], interfaces: [] };
if (sourceFile && lodash_1.default.includes(filePaths, sourceFile.fileName)) {
if (!this.hasClassDefinition(sourceFile)) {
const exports = this.getExports(sourceFile);
const firstExport = exports[0];
if (firstExport) {
const declaration = this.getClassDeclarationFromImportedFile(firstExport, (0, path_1.dirname)(tsFile), program);
if (declaration) {
const { classes, interfaces } = getDeclarationsFromNode(declaration, checker, sourceFile);
results.classes.push(...classes);
results.interfaces.push(...interfaces);
}
else {
// must have imported from somewhere else (another node module)
const className = //@ts-ignore
firstExport.exportClause?.elements?.[0]
?.propertyName?.text;
if (className) {
results.classes.push({
className,
classPath: tsFile,
isAbstract: false,
optionsInterfaceName: undefined,
parentClassName: undefined,
parentClassPath: undefined,
staticProperties: {},
});
}
}
}
}
else {
ts.forEachChild(sourceFile, (node) => {
const { classes, interfaces } = getDeclarationsFromNode(node, checker, sourceFile);
results.classes.push(...classes);
results.interfaces.push(...interfaces);
});
}
}
introspects.push(results);
}
return introspects;
},
getExports(sourceFile) {
const exports = [];
const traverse = (node) => {
if (ts.isExportDeclaration(node)) {
exports.push(node);
}
ts.forEachChild(node, traverse);
};
traverse(sourceFile);
return exports;
},
getClassDeclarationFromImportedFile(exportDeclaration, dirName, program) {
if (!ts.isExportDeclaration(exportDeclaration)) {
return undefined;
}
const exportClause = exportDeclaration.exportClause;
if (!exportClause || !ts.isNamedExports(exportClause)) {
return undefined;
}
for (const element of exportClause.elements) {
if (element.propertyName) {
const propertyName = element.propertyName.text;
const moduleSpecifier = exportDeclaration.moduleSpecifier.text;
const sourceFile = spruce_skill_utils_1.diskUtil.resolveFile(dirName, moduleSpecifier.replace(/^\.\//, ''));
if (!sourceFile) {
return undefined;
}
// Load the source file containing the class declaration
const declarationSourceFile = program.getSourceFile(sourceFile);
if (!declarationSourceFile) {
return undefined;
}
const traverse = (node) => {
if (ts.isClassDeclaration(node) &&
node.name &&
node.name.text === propertyName) {
return node;
}
for (const child of node.getChildren(declarationSourceFile)) {
const result = traverse(child);
if (result) {
return result;
}
}
return undefined;
};
return traverse(declarationSourceFile);
}
}
return undefined;
},
hasClassDefinition(sourceFile) {
let hasClass = false;
const traverse = (node) => {
if (ts.isClassDeclaration(node)) {
hasClass = true;
}
if (!hasClass) {
ts.forEachChild(node, traverse);
}
};
traverse(sourceFile);
return hasClass;
},
};
exports.default = introspectionUtil;
function getDeclarationsFromNode(node, checker, sourceFile) {
const classes = [];
const interfaces = [];
// if this is a class declaration
if (ts.isClassDeclaration(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
if (symbol?.valueDeclaration) {
const details = serializeSymbol({ checker, symbol });
// Get the construct signatures
const constructorType = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
let parentClassSymbol;
if (node.heritageClauses && node.heritageClauses[0]) {
parentClassSymbol = checker
.getTypeAtLocation(node.heritageClauses[0].types[0])
.getSymbol();
}
const parentClassName =
// @ts-ignore
parentClassSymbol?.valueDeclaration?.name?.text;
// @ts-ignore
const parentClassPath = parentClassSymbol?.parent
?.getName()
.replace('"', '');
const isAbstractClass = tsutils.isModifierFlagSet(node, ts.ModifierFlags.Abstract);
details.constructors = constructorType
.getConstructSignatures()
.map((s) => serializeSignature({ signature: s, checker }));
classes.push({
className: node.name.text,
classPath: sourceFile.fileName,
parentClassName,
parentClassPath,
staticProperties: pluckStaticProperties(node),
optionsInterfaceName: details.constructors?.[0].parameters?.[0]?.type,
isAbstract: isAbstractClass,
});
}
}
else if (ts.isInterfaceDeclaration(node)) {
interfaces.push({
interfaceName: node.name.text,
});
}
return { classes, interfaces };
}
function pluckStaticProperties(node) {
const staticProps = {};
for (const member of node.members) {
//@ts-ignore
const name = member.name?.escapedText;
//@ts-ignore
const value = member.initializer?.text;
if (name && value) {
staticProps[name] = value;
}
}
return staticProps;
}
//# sourceMappingURL=introspection.utility.js.map
;