beyond
Version:
The Full Stack Universal Typescript Framework
100 lines (80 loc) • 3.63 kB
JavaScript
const ts = require('typescript');
const {factory} = ts;
const tsKind = ts.SyntaxKind;
const printer = ts.createPrinter();
/**
* Process a bridge source file
*
* @param source {object} The source being analyzed
* @param distribution {object} The distribution specification
* @return {{content: string, info: Map<any, any>} | undefined}
* If undefined, it means that the source that not expose any actions
*/
module.exports = function (source, distribution) {
const {content} = source;
const {file} = source.relative;
let info = new Map();
if (!content) return {content, info};
const tsource = ts.createSourceFile(file, content);
// Traverse AST
let found = false;
const traverse = context => root => {
const analyze = node => {
if (node.kind === ts.SyntaxKind.SourceFile) return ts.visitEachChild(node, analyze, context);
// Check if node has the 'export' modifier
if (!ts.isClassDeclaration(node) || !node.modifiers ||
!node.modifiers.find(modifier => modifier.kind === tsKind.ExportKeyword)) {
return node.kind === tsKind.InterfaceDeclaration ? node : null;
}
// Check if node specifies that it is an actions class
const check = node => {
const text = tsource.text.substr(node.getStart(tsource), 20);
return /\/\*(\s*)actions(\s*)\*\//.test(text);
};
if (!node.name || !check(node)) return null;
const className = node.name.escapedText;
if (!className) return null;
found = true;
const heritage = factory.createHeritageClause(
ts.SyntaxKind.ExtendsKeyword,
[factory.createExpressionWithTypeArguments(
factory.createIdentifier('ActionsBridge'),
undefined
)]
);
node = factory.updateClassDeclaration(node, node.decorators, node.modifiers,
node.name, node.typeParameters, factory.createNodeArray([heritage]), node.members);
// Remove constructor
node.members = node.members.filter(member => !ts.isConstructorDeclaration(member));
const constructor = factory.createConstructorDeclaration(
undefined,
undefined,
[],
factory.createBlock(
[factory.createExpressionStatement(factory.createCallExpression(
factory.createSuper(),
undefined,
[
factory.createStringLiteral(distribution.backend ? distribution.backend : 'unknown'),
factory.createIdentifier('bundle')
]
))],
true
)
);
node.members.push(constructor);
// At this point, the node is a BeyondJS actions class
const parsed = require('./methods')(file, className, node, context);
info.set(className, parsed.info);
return parsed.node;
}
return ts.visitNode(root, analyze, context);
};
const result = ts.transform(tsource, [traverse]);
if (!found) return;
const code =
`import {bundle} from 'beyond_context';\n` +
`declare const ActionsBridge: any;\n` +
printer.printFile(result.transformed[0]);
return {content: code, info};
}