Skip to content

Instantly share code, notes, and snippets.

View roytouw7's full-sized avatar

Roy Touw roytouw7

  • New Story
  • Netherlands
View GitHub Profile
// Recursively visit every node in sourcefile.
const visitSourceFile = (sourceFile: ts.SourceFile, context: ts.TransformationContext): ts.SourceFile => {
const imports = new Set<RxJSPart>();
const visitNodes = (node: ts.Node): ts.Node => {
const [dispatchedNode, classification] = dispatch(node);
imports.add(classification);
return ts.visitEachChild(dispatchedNode, visitNodes, context);
};
// Recursively visit every node in sourcefile.
const visitSourceFile = (sourceFile: ts.SourceFile, context: ts.TransformationContext): ts.SourceFile => {
const imports = new Set<RxJSPart>();
const visitNodes = (node: ts.Node): ts.Node => {
const [dispatchedNode, classification] = dispatch(node);
imports.add(classification);
return ts.visitEachChild(dispatchedNode, visitNodes, context);
};
// Classify node, dispatch to appropriate wrapper function.
export const dispatch = (node: Touched<ts.Node>): [Transformed<ts.Node>, RxJSPart] => {
const classification = classify(node);
switch (classification) {
case RxJSPart.observable: {
const transformed = markAsTransformed(wrapObservableStatement(node as ts.CallExpression));
return [transformed, classification];
}
case RxJSPart.subscriber: {
export const isObjectOrSubjectConstructor: Classifier = classifierTemplate((node) => {
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)) {
if ([...rxjsObjectKinds, ...rxjsSubjectKinds].some(operator => operator === node.expression.getText())) {
return true;
}
}
return false;
});
// Classify node by set of classifiers, if classified return true.
export const isObjectOrSubjectConstructor: Classifier = classifierTemplate((node) => {
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)) {
if ([...rxjsObjectKinds, ...rxjsSubjectKinds].some(operator => operator === node.expression.getText())) {
return true;
}
}
return false;
});
// Classify node by set of classifiers, if classified return true.
export const isObjectOrSubjectConstructor: Classifier = classifierTemplate((node) => {
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)) {
if ([...rxjsObjectKinds, ...rxjsSubjectKinds].some(operator => operator === node.expression.getText())) {
return true;
}
}
return false;
});
import * as ts from 'typescript';
const printer = ts.createPrinter();
// Create ts.Node from given typescript code.
export const createNode = <T extends ts.Node>(code: string, type: number): [T, ts.SourceFile] => {
const sourcefile = ts.createSourceFile('test.ts', code, ts.ScriptTarget.ES2015, true);
const node = fetchNodeFromSourceFile(sourcefile);
if (node.kind !== type) {
throw new Error(`TypeScript node created from given code doesn't match expected type, expected: ${type} but compiled: ${node.kind}!`);
test('isObjectOrSubjectConstructor should identifiy RxJS Subject or Object contructor nodes.', () => {
const [node] = createNode<ts.NewExpression>(`new Observable();`, ts.SyntaxKind.NewExpression);
const [node2] = createNode<ts.NewExpression>(`new Observable<number>();`, ts.SyntaxKind.NewExpression);
const [node3] = createNode<ts.NewExpression>(`new BehaviorSubject<string>();`, ts.SyntaxKind.NewExpression);
const [node4] = createNode<ts.NewExpression>(`new NoRxJSSubject<string>();`, ts.SyntaxKind.NewExpression);
expect(isObjectOrSubjectConstructor(node)).toBe(true);
expect(isObjectOrSubjectConstructor(node2)).toBe(true);
expect(isObjectOrSubjectConstructor(node3)).toBe(true);
expect(isObjectOrSubjectConstructor(node4)).toBe(false);
// Fetch identifier for given node in AST if existing.
export const fetchIdentifier = (node: ts.Node): string | null => {
if (!ts.isPropertyDeclaration(node) && !ts.isVariableDeclaration(node) && !ts.isExpressionStatement(node)) {
return fetchIdentifier(node.parent);
} else if (ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
return node.name.getText();
} else {
return null;
}
};
// Create TypeScript property with given name and value, primitive literal values only.
const createPrimitiveProperty = (name: string, value: any) => ts.createPropertyAssignment(name, ts.createLiteral(defined(value)));
// Turn metadata object into TypeScript ObjectLiteralExpression.
const createMetadataObjectLiteral = (metadata: Metadata): ts.ObjectLiteralExpression => {
return ts.createObjectLiteral([
createPrimitiveProperty('uuid', metadata.uuid),
createPrimitiveProperty('part', metadata.part),
createPrimitiveProperty('observable', metadata.observable),
createPrimitiveProperty('identifier', metadata.identifier),