@ply-ct/ply
Version:
REST API Automated Testing
213 lines • 9.04 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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ts = void 0;
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const ts = __importStar(require("typescript"));
const glob = __importStar(require("glob"));
class Ts {
constructor(tsConfig = 'tsconfig.json', sourcePatterns = ['src/**/*.ts']) {
let files = [];
for (const sourcePattern of sourcePatterns) {
files = [...files, ...glob.sync(sourcePattern)];
}
const configPath = ts.findConfigFile('.', ts.sys.fileExists, tsConfig);
if (!configPath) {
throw new Error("Could not find a valid 'tsconfig.json' from " + path.resolve('.'));
}
const configContents = fs.readFileSync(configPath).toString();
const compilerOptions = ts.parseConfigFileTextToJson(configPath, configContents);
this.program = ts.createProgram(files, compilerOptions);
this.checker = this.program.getTypeChecker();
}
scanClassDecorators(decs) {
let decorators = [];
for (const sourceFile of this.program
.getSourceFiles()
.filter((sf) => !sf.isDeclarationFile)) {
ts.forEachChild(sourceFile, (node) => {
if (ts.isClassDeclaration(node) && node.name && Ts.isExported(node)) {
decorators = [
...decorators,
...this.findClassDecorators(sourceFile, node, decs)
];
}
});
}
return decorators;
}
findClassDecorators(sourceFile, classDeclaration, decs) {
const classDecs = [];
const classSymbol = this.checker.getSymbolAtLocation(classDeclaration.name);
if (classSymbol) {
let decorators;
if (ts.getDecorators) {
decorators = ts.getDecorators(classDeclaration);
}
else {
// old typescript compiler sdk incompatible
decorators = classDeclaration.decorators;
}
if (decorators) {
for (const decorator of decorators) {
const decoratorSymbol = this.getDecoratorSymbol(decorator);
if (decoratorSymbol) {
const decoratorType = this.checker.getAliasedSymbol(decoratorSymbol).name;
if (decs.includes(decoratorType)) {
classDecs.push({
file: sourceFile.fileName,
class: classSymbol.name,
decorator: decoratorType,
...Ts.decoratorArgs(decorator)
});
}
}
}
}
}
return classDecs;
}
findMethodDecorators(classDecorator, decs) {
const methodDecs = [];
const classDeclaration = this.getClassDeclaration(classDecorator.file, classDecorator.class);
if (classDeclaration) {
for (const methodDeclaration of Ts.methodDeclarations(classDeclaration)) {
const methodSymbol = this.checker.getSymbolAtLocation(methodDeclaration.name);
let decorators;
if (methodSymbol) {
if (ts.getDecorators) {
decorators = ts.getDecorators(methodDeclaration);
}
else {
// old typescript compiler sdk incompatible
decorators = methodDeclaration.decorators;
}
if (decorators) {
for (const decorator of decorators) {
const decoratorSymbol = this.getDecoratorSymbol(decorator);
if (decoratorSymbol) {
const decoratorType = this.checker.getAliasedSymbol(decoratorSymbol).name;
if (decs.includes(decoratorType)) {
methodDecs.push({
file: classDecorator.file,
class: classDecorator.class,
decorator: decoratorType,
method: methodSymbol.name,
...Ts.decoratorArgs(decorator)
});
}
}
}
}
}
}
}
return methodDecs;
}
getClassDeclaration(file, className) {
const sourceFile = this.program.getSourceFile(file);
if (sourceFile) {
let classDeclaration;
ts.forEachChild(sourceFile, (node) => {
if (ts.isClassDeclaration(node) && node.name && Ts.isExported(node)) {
const classDecl = node;
const classSymbol = this.checker.getSymbolAtLocation(classDecl.name);
if ((classSymbol === null || classSymbol === void 0 ? void 0 : classSymbol.name) === className) {
classDeclaration = classDecl;
}
}
});
return classDeclaration;
}
}
getDecoratorSymbol(decorator) {
if (decorator.expression) {
const firstToken = decorator.expression.getFirstToken();
if (firstToken) {
return this.checker.getSymbolAtLocation(firstToken);
}
else {
return this.checker.getSymbolAtLocation(decorator.expression);
}
}
}
static decoratorArgs(decorator) {
const args = {};
if (decorator.expression.getChildCount() >= 3) {
let text = decorator.expression.getChildAt(2).getText().trim();
if (decorator.expression.getChildAt(2).getChildCount() >= 3 &&
ts.isObjectLiteralExpression(decorator.expression.getChildAt(2).getChildAt(2))) {
args.args = Ts.parseObjectLiteral(decorator.expression.getChildAt(2).getChildAt(2));
text = decorator.expression.getChildAt(2).getChildAt(0).getText().trim();
}
args.arg = text.substring(1, text.length - 1);
}
return args;
}
static methodDeclarations(classDeclaration) {
const methodDeclaration = [];
classDeclaration.forEachChild((node) => {
if (ts.isMethodDeclaration(node) && !ts.isPrivateIdentifier(node)) {
methodDeclaration.push(node);
}
});
return methodDeclaration;
}
static symbolAtNode(node) {
return node.symbol;
}
static isExported(node) {
return ((ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 ||
(!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile));
}
/**
* Only handles simple types
*/
static parseObjectLiteral(objLit) {
var _a;
const res = {};
for (const prop of objLit.properties) {
const propName = (_a = prop.name) === null || _a === void 0 ? void 0 : _a.getText();
if (propName && prop.initializer) {
if (prop.initializer.text) {
res[propName] = prop.initializer.text;
}
else {
const textVal = prop.initializer.getText();
if (textVal === 'true' || textVal === 'false') {
res[propName] = textVal === 'true';
}
else if (parseInt(textVal)) {
res[propName] = parseInt(textVal);
}
}
}
}
return res;
}
}
exports.Ts = Ts;
//# sourceMappingURL=ts.js.map