UNPKG

@ibyar/cli

Version:

The Ibyar/Aurora CLI tool

248 lines 9.3 kB
import ts from 'typescript/lib/tsserverlibrary.js'; /** * check if a decorator is a `@Component` decorator; * @param decorator * @param expressionName * @returns */ export function isComponentDecorator(decorator, componentName = 'Component') { return ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === componentName; } ; /** * check if a decorator is a `@Directive` decorator; * @param decorator * @param directiveName * @returns */ export function isDirectiveDecorator(decorator, directiveName = 'Directive') { return ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === directiveName; } ; export function isComponentOrDirectiveDecorator(decorator, componentName = 'Component', directiveName = 'Directive') { return isComponentDecorator(decorator, componentName) || isDirectiveDecorator(decorator, directiveName); } ; /** * check if a decorator is a `@Pipe` decorator; * @param decorator * @param pipeName * @returns */ export function isPipeDecorator(decorator, pipeName = 'Pipe') { return ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === pipeName; } ; /** * check if a decorator is a `@Injectable` decorator; * @param decorator * @param injectableName * @returns */ export function isInjectableDecorator(decorator, injectableName = 'Injectable') { return ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === injectableName; } ; /** * check if Decorator is `@Input` or `@FormValue` * @param decorator * @returns */ export function isInputDecorator(decorator) { return ts.isCallExpression(decorator.expression) && (decorator.expression.expression.getText() === 'Input' || decorator.expression.expression.getText() === 'FormValue'); } /** * check if Decorator is `@Output` * @param decorator * @returns */ export function isOutputDecorator(decorator) { return ts.isCallExpression(decorator.expression) && decorator.expression.expression.getText() === 'Output'; } export function getMapByDecoratorForPropertyDeclaration(member, checker, decoratorFilter) { const infos = []; const decorators = ts.getDecorators(member); if (!decorators) { return infos; } const inputDecorators = decorators.filter(decoratorFilter); if (!inputDecorators.length) { return infos; } let inputType = member.type?.getText(); if (!inputType && member.initializer) { inputType = checker.typeToString(checker.getTypeAtLocation(member.initializer), member.initializer, undefined); } inputDecorators.forEach(input => { const decoratorCall = input.expression; const aliasName = decoratorCall.arguments[0]; const alias = aliasName ? aliasName.text : member.name.getText(); infos.push({ name: member.name.getText(), aliasName: alias, type: inputType }); }); return infos; } export function getMapByDecoratorForSetAccessorDeclaration(member, checker, decoratorFilter) { const infos = []; const decorators = ts.getDecorators(member); if (!decorators) { return infos; } const inputDecorators = decorators.filter(decoratorFilter); if (!inputDecorators.length) { return infos; } let memberName; if (ts.isIdentifier(member.name)) { memberName = member.name.getText(); } else if (ts.isComputedPropertyName(member.name) && ts.isStringLiteral(member.name.expression)) { memberName = member.name.expression.getText(); } else { return infos; } let inputType = checker.typeToString(checker.getTypeAtLocation(member.parameters[0]), member.parameters[0], undefined); inputDecorators.forEach(input => { const decoratorCall = input.expression; const aliasName = decoratorCall.arguments[0]; const alias = aliasName ? aliasName.text : memberName; infos.push({ name: memberName, aliasName: alias, type: inputType }); }); return infos; } export function getMapByDecorator(classNode, checker, decoratorFilter) { const infos = []; classNode.members.forEach(member => { if (ts.isPropertyDeclaration(member)) { infos.push(...getMapByDecoratorForPropertyDeclaration(member, checker, decoratorFilter)); } else if (ts.isSetAccessorDeclaration(member)) { infos.push(...getMapByDecoratorForSetAccessorDeclaration(member, checker, decoratorFilter)); } }); return infos; } /** * get a component or directive inputs that is annotated by `@Input` or `@FormValue`. * @param classNode * @param checker * @returns */ export function getInputs(classNode, checker) { return getMapByDecorator(classNode, checker, isInputDecorator); } /** * get a component or directive input names that is annotated by `@Input` or `@FormValue`. * @param classNode * @param checker * @returns */ export function getInputNames(classNode, checker) { return getInputs(classNode, checker).map(info => info.aliasName); } /** * get a component or directive outputs that is annotated by `@Output`. * @param classNode * @param checker * @returns */ export function getOutputs(classNode, checker) { return getMapByDecorator(classNode, checker, isOutputDecorator); } /** * get a component or directive output names that is annotated by `@Output`. * @param classNode * @param checker * @returns */ export function getOutputNames(classNode, checker) { return getOutputs(classNode, checker).map(info => info.aliasName); } /** * get text value for a property in ObjectLiteralExpression * @param option * @param property * @returns */ export function getTextValueFormLiteralProperty(option, property) { const selectorProperty = option.properties .find(prop => prop.name?.getText() === property); const initializer = selectorProperty?.initializer.getText(); if (!initializer) { return; } return initializer?.substring(1, initializer.length - 1); } /** * get text value for a property in ObjectLiteralExpression * @param option * @param property * @returns */ export function getTextValueFormArrayLiteralProperty(option, property) { const selectorProperty = option.properties .find(prop => prop.name?.getText() === property); if (!selectorProperty?.initializer || !ts.isArrayLiteralExpression(selectorProperty.initializer)) { return []; } return selectorProperty.initializer.elements .map(initializer => initializer.getText()) .map(initializer => initializer.substring(1, initializer.length - 1)); } export function scanAliasName(call) { const alias = call.arguments .filter(expr => ts.isObjectLiteralExpression(expr)) .flatMap(expr => expr.properties) .filter(expr => ts.isPropertyAssignment(expr) && ts.isStringLiteral(expr.initializer) && ts.isIdentifier(expr.name) && expr.name.getText() === 'alias') .at(0); const initializer = alias?.initializer.getText(); return initializer?.substring(1, initializer.length - 1); } export function scanSignalCall(call, signalKey, name) { const type = call.typeArguments?.[0].getText(); if (ts.isIdentifier(call.expression) && call.expression.getText() === signalKey) { return { name, type, aliasName: scanAliasName(call) ?? name }; } else if (ts.isPropertyAccessExpression(call.expression) && ts.isIdentifier(call.expression.expression) && call.expression.expression.getText() === signalKey && ts.isIdentifier(call.expression.name) && call.expression.name.getText() === 'required') { return { name, type, necessity: 'required', aliasName: scanAliasName(call) ?? name }; } else if (ts.isElementAccessExpression(call.expression) && ts.isIdentifier(call.expression.expression) && call.expression.expression.getText() === signalKey && ts.isIdentifier(call.expression.argumentExpression) && call.expression.argumentExpression.getText() === 'required') { return { name, type, necessity: 'required', aliasName: scanAliasName(call) ?? name }; } return false; } /** * get component and directive signals that is evaluated with `input`, `output`, ... etc. * @param classNode * @param signals * @returns */ export function scanSignals(classNode, signals) { const infos = {}; const members = classNode.members .filter(member => ts.isPropertyDeclaration(member) && member.initializer && ts.isCallExpression(member.initializer)); Object.entries(signals).forEach(([alias, signal]) => { members.forEach(member => { const name = (ts.isComputedPropertyName(member.name) && ts.isStringLiteral(member.name.expression)) ? member.name.expression.getText() : member.name.getText(); const info = scanSignalCall(member.initializer, alias, checkAndRemoveQuotations(name)); info && (infos[signal] ??= []).push(info); }); }); return infos; } function checkAndRemoveQuotations(string) { if (/(^'.*'$)|(^".*"$)|(^`.*`$)/.test(string)) { return string.substring(1, string.length - 1); } return string; } //# sourceMappingURL=helpers.js.map