Exemple #1
0
 /**
  * Adds extra imports in the import manage for this source file, after the existing imports
  * and before the module body.
  * Can optionally add extra statements (e.g. new constants) before the body as well.
  */
 function addImports(importManager, sf, extraStatements) {
     if (extraStatements === void 0) { extraStatements = []; }
     // Generate the import statements to prepend.
     var addedImports = importManager.getAllImports(sf.fileName).map(function (i) {
         var qualifier = ts.createIdentifier(i.qualifier);
         var importClause = ts.createImportClause(
         /* name */ undefined, 
         /* namedBindings */ ts.createNamespaceImport(qualifier));
         return ts.createImportDeclaration(
         /* decorators */ undefined, 
         /* modifiers */ undefined, 
         /* importClause */ importClause, 
         /* moduleSpecifier */ ts.createLiteral(i.specifier));
     });
     // Filter out the existing imports and the source file body. All new statements
     // will be inserted between them.
     var existingImports = sf.statements.filter(function (stmt) { return isImportStatement(stmt); });
     var body = sf.statements.filter(function (stmt) { return !isImportStatement(stmt); });
     // Prepend imports if needed.
     if (addedImports.length > 0) {
         // If we prepend imports, we also prepend NotEmittedStatement to use it as an anchor
         // for @fileoverview Closure annotation. If there is no @fileoverview annotations, this
         // statement would be a noop.
         var fileoverviewAnchorStmt = ts.createNotEmittedStatement(sf);
         sf.statements = ts.createNodeArray(tslib_1.__spread([fileoverviewAnchorStmt], existingImports, addedImports, extraStatements, body));
     }
     return sf;
 }
 IvyVisitor.prototype._nonCoreDecoratorsOnly = function (node) {
     // Shortcut if the node has no decorators.
     if (node.decorators === undefined) {
         return undefined;
     }
     // Build a Set of the decorators on this node from @angular/core.
     var coreDecorators = this._angularCoreDecorators(node);
     if (coreDecorators.size === node.decorators.length) {
         // If all decorators are to be removed, return `undefined`.
         return undefined;
     }
     else if (coreDecorators.size === 0) {
         // If no decorators need to be removed, return the original decorators array.
         return node.decorators;
     }
     // Filter out the core decorators.
     var filtered = node.decorators.filter(function (dec) { return !coreDecorators.has(dec); });
     // If no decorators survive, return `undefined`. This can only happen if a core decorator is
     // repeated on the node.
     if (filtered.length === 0) {
         return undefined;
     }
     // Create a new `NodeArray` with the filtered decorators that sourcemaps back to the original.
     var array = ts.createNodeArray(filtered);
     array.pos = node.decorators.pos;
     array.end = node.decorators.end;
     return array;
 };
Exemple #3
0
exports.getComponentDecorator = function (declaration) {
    return ts.createNodeArray(declaration.decorators).find(function (d) {
        return (ts.isCallExpression(d.expression) &&
            d.expression.arguments &&
            d.expression.arguments.length > 0 &&
            exports.getDecoratorName(d) === 'Component');
    });
};
Exemple #4
0
exports.getDecoratorPropertyInitializer = function (decorator, name) {
    var args = ts.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
    var properties = ts.createNodeArray(args && ts.isObjectLiteralExpression(args) ? args.properties : undefined);
    return properties
        .filter(function (prop) { return prop.name && ts.isIdentifier(prop.name) && prop.name.text === name; })
        .map(function (prop) { return (ts.isPropertyAssignment(prop) ? prop.initializer : undefined); })
        .pop();
};
 /**
  * For each property in the object literal, if it's templateUrl or styleUrls, replace it
  * with content.
  * @param node the arguments to @Component() or args property of decorators: [{type:Component}]
  * @param loader provides access to the loadResource method of the host
  * @returns updated arguments
  */
 function updateComponentProperties(args, loader) {
     if (args.length !== 1) {
         // User should have gotten a type-check error because @Component takes one argument
         return args;
     }
     var componentArg = args[0];
     if (!ts.isObjectLiteralExpression(componentArg)) {
         // User should have gotten a type-check error because @Component takes an object literal
         // argument
         return args;
     }
     var newProperties = [];
     var newStyleExprs = [];
     componentArg.properties.forEach(function (prop) {
         if (!ts.isPropertyAssignment(prop) || ts.isComputedPropertyName(prop.name)) {
             newProperties.push(prop);
             return;
         }
         switch (prop.name.text) {
             case 'styles':
                 if (!ts.isArrayLiteralExpression(prop.initializer)) {
                     throw new Error('styles takes an array argument');
                 }
                 newStyleExprs.push.apply(newStyleExprs, tslib_1.__spread(prop.initializer.elements));
                 break;
             case 'styleUrls':
                 if (!ts.isArrayLiteralExpression(prop.initializer)) {
                     throw new Error('styleUrls takes an array argument');
                 }
                 newStyleExprs.push.apply(newStyleExprs, tslib_1.__spread(prop.initializer.elements.map(function (expr) {
                     if (!ts.isStringLiteral(expr) && !ts.isNoSubstitutionTemplateLiteral(expr)) {
                         throw new Error('Can only accept string literal arguments to styleUrls. ' + PRECONDITIONS_TEXT);
                     }
                     var styles = loader.get(expr.text);
                     return ts.createLiteral(styles);
                 })));
                 break;
             case 'templateUrl':
                 if (!ts.isStringLiteral(prop.initializer) &&
                     !ts.isNoSubstitutionTemplateLiteral(prop.initializer)) {
                     throw new Error('Can only accept a string literal argument to templateUrl. ' + PRECONDITIONS_TEXT);
                 }
                 var template = loader.get(prop.initializer.text);
                 newProperties.push(ts.updatePropertyAssignment(prop, ts.createIdentifier('template'), ts.createLiteral(template)));
                 break;
             default:
                 newProperties.push(prop);
         }
     });
     // Add the non-inline styles
     if (newStyleExprs.length > 0) {
         var newStyles = ts.createPropertyAssignment(ts.createIdentifier('styles'), ts.createArrayLiteral(newStyleExprs));
         newProperties.push(newStyles);
     }
     return ts.createNodeArray([ts.updateObjectLiteral(componentArg, newProperties)]);
 }
 function maybeFilterDecorator(decorators, toRemove) {
     if (decorators === undefined) {
         return undefined;
     }
     var filtered = decorators.filter(function (dec) { return toRemove.find(function (decToRemove) { return ts.getOriginalNode(dec) === decToRemove; }) === undefined; });
     if (filtered.length === 0) {
         return undefined;
     }
     return ts.createNodeArray(filtered);
 }
 NgWalker.prototype.visitClassDeclaration = function (declaration) {
     var metadata = this._metadataReader.read(declaration);
     if (metadata instanceof metadata_1.ComponentMetadata) {
         this.visitNgComponent(metadata);
     }
     else if (metadata instanceof metadata_1.DirectiveMetadata) {
         this.visitNgDirective(metadata);
     }
     utils_1.maybeNodeArray(ts.createNodeArray(declaration.decorators)).forEach(this.visitClassDecorator.bind(this));
     _super.prototype.visitClassDeclaration.call(this, declaration);
 };
Exemple #8
0
 /**
  * A transformer which operates on ts.SourceFiles and applies changes from an `IvyCompilation`.
  */
 function transformIvySourceFile(compilation, context, reflector, coreImportsFrom, file) {
     var importManager = new translator_1.ImportManager(coreImportsFrom !== null);
     // Recursively scan through the AST and perform any updates requested by the IvyCompilation.
     var sf = visitor_1.visit(file, new IvyVisitor(compilation, reflector, importManager, coreImportsFrom !== null), context);
     // Generate the import statements to prepend.
     var imports = importManager.getAllImports(file.fileName, coreImportsFrom).map(function (i) {
         return ts.createImportDeclaration(undefined, undefined, ts.createImportClause(undefined, ts.createNamespaceImport(ts.createIdentifier(i.as))), ts.createLiteral(i.name));
     });
     // Prepend imports if needed.
     if (imports.length > 0) {
         sf.statements = ts.createNodeArray(tslib_1.__spread(imports, sf.statements));
     }
     return sf;
 }
 function transformFactorySourceFile(factoryMap, context, coreImportsFrom, file) {
     // If this is not a generated file, it won't have factory info associated with it.
     if (!factoryMap.has(file.fileName)) {
         // Don't transform non-generated code.
         return file;
     }
     var _a = factoryMap.get(file.fileName), moduleSymbolNames = _a.moduleSymbolNames, sourceFilePath = _a.sourceFilePath;
     var clone = ts.getMutableClone(file);
     var transformedStatements = file.statements.map(function (stmt) {
         if (coreImportsFrom !== null && ts.isImportDeclaration(stmt) &&
             ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === '@angular/core') {
             var path = path_1.relativePathBetween(sourceFilePath, coreImportsFrom.fileName);
             if (path !== null) {
                 return ts.updateImportDeclaration(stmt, stmt.decorators, stmt.modifiers, stmt.importClause, ts.createStringLiteral(path));
             }
             else {
                 return ts.createNotEmittedStatement(stmt);
             }
         }
         else if (ts.isVariableStatement(stmt) && stmt.declarationList.declarations.length === 1) {
             var decl = stmt.declarationList.declarations[0];
             if (ts.isIdentifier(decl.name)) {
                 var match = STRIP_NG_FACTORY.exec(decl.name.text);
                 if (match === null || !moduleSymbolNames.has(match[1])) {
                     // Remove the given factory as it wasn't actually for an NgModule.
                     return ts.createNotEmittedStatement(stmt);
                 }
             }
             return stmt;
         }
         else {
             return stmt;
         }
     });
     if (!transformedStatements.some(ts.isVariableStatement)) {
         // If the resulting file has no factories, include an empty export to
         // satisfy closure compiler.
         transformedStatements.push(ts.createVariableStatement([ts.createModifier(ts.SyntaxKind.ExportKeyword)], ts.createVariableDeclarationList([ts.createVariableDeclaration('ɵNonEmptyModule', undefined, ts.createTrue())], ts.NodeFlags.Const)));
     }
     clone.statements = ts.createNodeArray(transformedStatements);
     return clone;
 }
Exemple #10
0
/**
 * Convert leading/trailing detached comment ranges of statement arrays
 * (e.g. the statements of a ts.SourceFile or ts.Block) into
 * `ts.NonEmittedStatement`s with `ts.SynthesizedComment`s and
 * prepends / appends them to the given statement array.
 * This is needed to allow changing these comments.
 *
 * This function takes a visitor to be able to do some
 * state management after the caller is done changing a node.
 */
function visitNodeStatementsWithSynthesizedComments(context, sourceFile, node, statements, visitor) {
    var leading = synthesizeDetachedLeadingComments(sourceFile, node, statements);
    var trailing = synthesizeDetachedTrailingComments(sourceFile, node, statements);
    if (leading.commentStmt || trailing.commentStmt) {
        statements = ts.setTextRange(ts.createNodeArray(statements), { pos: -1, end: -1 });
        if (leading.commentStmt) {
            statements.unshift(leading.commentStmt);
        }
        if (trailing.commentStmt) {
            statements.push(trailing.commentStmt);
        }
        var fileContext = assertFileContext(context, sourceFile);
        if (leading.lastCommentEnd !== -1) {
            fileContext.lastCommentEnd = leading.lastCommentEnd;
        }
        node = visitor(node, statements);
        if (trailing.lastCommentEnd !== -1) {
            fileContext.lastCommentEnd = trailing.lastCommentEnd;
        }
        return node;
    }
    return visitor(node, statements);
}
Exemple #11
0
function visitBlockStatements(statements, context) {
    // copy of statements to modify; lazy initialized
    let updatedStatements;
    const visitor = (node) => {
        if (isBlockLike(node)) {
            const result = visitBlockStatements(node.statements, context);
            if (result === node.statements) {
                return node;
            }
            switch (node.kind) {
                case ts.SyntaxKind.Block:
                    return ts.updateBlock(node, result);
                case ts.SyntaxKind.ModuleBlock:
                    return ts.updateModuleBlock(node, result);
                case ts.SyntaxKind.CaseClause:
                    const clause = node;
                    return ts.updateCaseClause(clause, clause.expression, result);
                case ts.SyntaxKind.DefaultClause:
                    return ts.updateDefaultClause(node, result);
                default:
                    return node;
            }
        }
        else {
            return ts.visitEachChild(node, visitor, context);
        }
    };
    // 'oIndex' is the original statement index; 'uIndex' is the updated statement index
    for (let oIndex = 0, uIndex = 0; oIndex < statements.length; oIndex++, uIndex++) {
        const currentStatement = statements[oIndex];
        // these can't contain an enum declaration
        if (currentStatement.kind === ts.SyntaxKind.ImportDeclaration) {
            continue;
        }
        // enum declarations must:
        //   * not be last statement
        //   * be a variable statement
        //   * have only one declaration
        //   * have an identifer as a declaration name
        if (oIndex < statements.length - 1
            && isVariableStatement(currentStatement)
            && currentStatement.declarationList.declarations.length === 1) {
            const variableDeclaration = currentStatement.declarationList.declarations[0];
            if (isIdentifier(variableDeclaration.name)) {
                const name = variableDeclaration.name.text;
                if (!variableDeclaration.initializer) {
                    const enumStatements = findTs2_3EnumStatements(name, statements[oIndex + 1]);
                    if (enumStatements.length > 0) {
                        // found an enum
                        if (!updatedStatements) {
                            updatedStatements = statements.slice();
                        }
                        // create wrapper and replace variable statement and IIFE
                        updatedStatements.splice(uIndex, 2, createWrappedEnum(name, currentStatement, enumStatements, undefined));
                        // skip IIFE statement
                        oIndex++;
                        continue;
                    }
                }
                else if (isObjectLiteralExpression(variableDeclaration.initializer)
                    && variableDeclaration.initializer.properties.length === 0) {
                    const nextStatements = statements.slice(oIndex + 1);
                    const enumStatements = findTs2_2EnumStatements(name, nextStatements);
                    if (enumStatements.length > 0) {
                        // found an enum
                        if (!updatedStatements) {
                            updatedStatements = statements.slice();
                        }
                        // create wrapper and replace variable statement and enum member statements
                        updatedStatements.splice(uIndex, enumStatements.length + 1, createWrappedEnum(name, currentStatement, enumStatements, variableDeclaration.initializer));
                        // skip enum member declarations
                        oIndex += enumStatements.length;
                        continue;
                    }
                }
                else if (isObjectLiteralExpression(variableDeclaration.initializer)
                    && variableDeclaration.initializer.properties.length !== 0) {
                    const literalPropertyCount = variableDeclaration.initializer.properties.length;
                    const nextStatements = statements.slice(oIndex + 1);
                    const enumStatements = findTsickleEnumStatements(name, nextStatements);
                    if (enumStatements.length === literalPropertyCount) {
                        // found an enum
                        if (!updatedStatements) {
                            updatedStatements = statements.slice();
                        }
                        // create wrapper and replace variable statement and enum member statements
                        updatedStatements.splice(uIndex, enumStatements.length + 1, createWrappedEnum(name, currentStatement, enumStatements, variableDeclaration.initializer));
                        // skip enum member declarations
                        oIndex += enumStatements.length;
                        continue;
                    }
                }
            }
        }
        const result = ts.visitNode(currentStatement, visitor);
        if (result !== currentStatement) {
            if (!updatedStatements) {
                updatedStatements = statements.slice();
            }
            updatedStatements[uIndex] = result;
        }
    }
    // if changes, return updated statements
    // otherwise, return original array instance
    return updatedStatements ? ts.createNodeArray(updatedStatements) : statements;
}
Exemple #12
0
 function visitSourceFile(sourceFile) {
     function topLevelStatement(node) {
         var declarations = [];
         function visitNode(node) {
             // Get the original node before tsickle
             var _a = ts.getOriginalNode(node), pos = _a.pos, end = _a.end, kind = _a.kind, originalParent = _a.parent;
             var nodeRequest = requests.get(pos);
             if (nodeRequest && nodeRequest.kind == kind && nodeRequest.end == end) {
                 // This node is requested to be rewritten as a reference to the exported name.
                 if (originalParent && originalParent.kind === ts.SyntaxKind.VariableDeclaration) {
                     // As the value represents the whole initializer of a variable declaration,
                     // just refer to that variable. This e.g. helps to preserve closure comments
                     // at the right place.
                     var varParent = originalParent;
                     if (varParent.name.kind === ts.SyntaxKind.Identifier) {
                         var varName = varParent.name.text;
                         var exportName_1 = nodeRequest.name;
                         declarations.push({
                             name: exportName_1,
                             node: ts.createIdentifier(varName),
                             order: 1 /* AfterStmt */
                         });
                         return node;
                     }
                 }
                 // Record that the node needs to be moved to an exported variable with the given name
                 var exportName = nodeRequest.name;
                 declarations.push({ name: exportName, node: node, order: 0 /* BeforeStmt */ });
                 return ts.createIdentifier(exportName);
             }
             var result = node;
             if (shouldVisit(pos, end) && !isLexicalScope(node)) {
                 result = ts.visitEachChild(node, visitNode, context);
             }
             return result;
         }
         // Get the original node before tsickle
         var _a = ts.getOriginalNode(node), pos = _a.pos, end = _a.end;
         var resultStmt;
         if (shouldVisit(pos, end)) {
             resultStmt = ts.visitEachChild(node, visitNode, context);
         }
         else {
             resultStmt = node;
         }
         if (declarations.length) {
             inserts.push({ relativeTo: resultStmt, declarations: declarations });
         }
         return resultStmt;
     }
     var newStatements = sourceFile.statements.map(topLevelStatement);
     if (inserts.length) {
         // Insert the declarations relative to the rewritten statement that references them.
         var insertMap_1 = toMap(inserts, function (i) { return i.relativeTo; });
         var tmpStatements_1 = [];
         newStatements.forEach(function (statement) {
             var insert = insertMap_1.get(statement);
             if (insert) {
                 var before = insert.declarations.filter(function (d) { return d.order === 0 /* BeforeStmt */; });
                 if (before.length) {
                     tmpStatements_1.push(createVariableStatementForDeclarations(before));
                 }
                 tmpStatements_1.push(statement);
                 var after = insert.declarations.filter(function (d) { return d.order === 1 /* AfterStmt */; });
                 if (after.length) {
                     tmpStatements_1.push(createVariableStatementForDeclarations(after));
                 }
             }
             else {
                 tmpStatements_1.push(statement);
             }
         });
         // Insert an exports clause to export the declarations
         tmpStatements_1.push(ts.createExportDeclaration(
         /* decorators */ undefined, 
         /* modifiers */ undefined, ts.createNamedExports(inserts
             .reduce(function (accumulator, insert) { return accumulator.concat(insert.declarations); }, [])
             .map(function (declaration) { return ts.createExportSpecifier(
         /* propertyName */ undefined, declaration.name); }))));
         newStatements = tmpStatements_1;
     }
     // Note: We cannot use ts.updateSourcefile here as
     // it does not work well with decorators.
     // See https://github.com/Microsoft/TypeScript/issues/17384
     var newSf = ts.getMutableClone(sourceFile);
     if (!(sourceFile.flags & ts.NodeFlags.Synthesized)) {
         newSf.flags &= ~ts.NodeFlags.Synthesized;
     }
     newSf.statements = ts.setTextRange(ts.createNodeArray(newStatements), sourceFile.statements);
     return newSf;
 }
 NgWalker.prototype.visitPropertyDeclaration = function (prop) {
     utils_1.maybeNodeArray(ts.createNodeArray(prop.decorators)).forEach(this.visitPropertyDecorator.bind(this));
     _super.prototype.visitPropertyDeclaration.call(this, prop);
 };
 NgWalker.prototype.visitMethodDeclaration = function (method) {
     utils_1.maybeNodeArray(ts.createNodeArray(method.decorators)).forEach(this.visitMethodDecorator.bind(this));
     _super.prototype.visitMethodDeclaration.call(this, method);
 };
var getDecoratorStringArgs = function (decorator) {
    var expression = decorator.expression;
    var args = ts.isCallExpression(expression) ? expression.arguments : ts.createNodeArray();
    return args.filter(ts.isStringLiteral).map(function (x) { return x.text; });
};