[6a3a178] | 1 | "use strict";
|
---|
| 2 | /**
|
---|
| 3 | * @license
|
---|
| 4 | * Copyright Google LLC All Rights Reserved.
|
---|
| 5 | *
|
---|
| 6 | * Use of this source code is governed by an MIT-style license that can be
|
---|
| 7 | * found in the LICENSE file at https://angular.io/license
|
---|
| 8 | */
|
---|
| 9 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
---|
| 10 | if (k2 === undefined) k2 = k;
|
---|
| 11 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
---|
| 12 | }) : (function(o, m, k, k2) {
|
---|
| 13 | if (k2 === undefined) k2 = k;
|
---|
| 14 | o[k2] = m[k];
|
---|
| 15 | }));
|
---|
| 16 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
---|
| 17 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
---|
| 18 | }) : function(o, v) {
|
---|
| 19 | o["default"] = v;
|
---|
| 20 | });
|
---|
| 21 | var __importStar = (this && this.__importStar) || function (mod) {
|
---|
| 22 | if (mod && mod.__esModule) return mod;
|
---|
| 23 | var result = {};
|
---|
| 24 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
---|
| 25 | __setModuleDefault(result, mod);
|
---|
| 26 | return result;
|
---|
| 27 | };
|
---|
| 28 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 29 | exports.getWrapEnumsTransformer = void 0;
|
---|
| 30 | const ts = __importStar(require("typescript"));
|
---|
| 31 | const ast_utils_1 = require("../helpers/ast-utils");
|
---|
| 32 | function isBlockLike(node) {
|
---|
| 33 | return (node.kind === ts.SyntaxKind.Block ||
|
---|
| 34 | node.kind === ts.SyntaxKind.ModuleBlock ||
|
---|
| 35 | node.kind === ts.SyntaxKind.CaseClause ||
|
---|
| 36 | node.kind === ts.SyntaxKind.DefaultClause ||
|
---|
| 37 | node.kind === ts.SyntaxKind.SourceFile);
|
---|
| 38 | }
|
---|
| 39 | function getWrapEnumsTransformer() {
|
---|
| 40 | return (context) => {
|
---|
| 41 | const transformer = (sf) => {
|
---|
| 42 | const result = visitBlockStatements(sf.statements, context);
|
---|
| 43 | return context.factory.updateSourceFile(sf, ts.setTextRange(result, sf.statements));
|
---|
| 44 | };
|
---|
| 45 | return transformer;
|
---|
| 46 | };
|
---|
| 47 | }
|
---|
| 48 | exports.getWrapEnumsTransformer = getWrapEnumsTransformer;
|
---|
| 49 | function visitBlockStatements(statements, context) {
|
---|
| 50 | // copy of statements to modify; lazy initialized
|
---|
| 51 | let updatedStatements;
|
---|
| 52 | const nodeFactory = context.factory;
|
---|
| 53 | const visitor = (node) => {
|
---|
| 54 | if (isBlockLike(node)) {
|
---|
| 55 | let result = visitBlockStatements(node.statements, context);
|
---|
| 56 | if (result === node.statements) {
|
---|
| 57 | return node;
|
---|
| 58 | }
|
---|
| 59 | result = ts.setTextRange(result, node.statements);
|
---|
| 60 | switch (node.kind) {
|
---|
| 61 | case ts.SyntaxKind.Block:
|
---|
| 62 | return nodeFactory.updateBlock(node, result);
|
---|
| 63 | case ts.SyntaxKind.ModuleBlock:
|
---|
| 64 | return nodeFactory.updateModuleBlock(node, result);
|
---|
| 65 | case ts.SyntaxKind.CaseClause:
|
---|
| 66 | return nodeFactory.updateCaseClause(node, node.expression, result);
|
---|
| 67 | case ts.SyntaxKind.DefaultClause:
|
---|
| 68 | return nodeFactory.updateDefaultClause(node, result);
|
---|
| 69 | default:
|
---|
| 70 | return node;
|
---|
| 71 | }
|
---|
| 72 | }
|
---|
| 73 | else {
|
---|
| 74 | return node;
|
---|
| 75 | }
|
---|
| 76 | };
|
---|
| 77 | // 'oIndex' is the original statement index; 'uIndex' is the updated statement index
|
---|
| 78 | for (let oIndex = 0, uIndex = 0; oIndex < statements.length - 1; oIndex++, uIndex++) {
|
---|
| 79 | const currentStatement = statements[oIndex];
|
---|
| 80 | let newStatement;
|
---|
| 81 | let oldStatementsLength = 0;
|
---|
| 82 | // these can't contain an enum declaration
|
---|
| 83 | if (currentStatement.kind === ts.SyntaxKind.ImportDeclaration) {
|
---|
| 84 | continue;
|
---|
| 85 | }
|
---|
| 86 | // enum declarations must:
|
---|
| 87 | // * not be last statement
|
---|
| 88 | // * be a variable statement
|
---|
| 89 | // * have only one declaration
|
---|
| 90 | // * have an identifer as a declaration name
|
---|
| 91 | // ClassExpression declarations must:
|
---|
| 92 | // * not be last statement
|
---|
| 93 | // * be a variable statement
|
---|
| 94 | // * have only one declaration
|
---|
| 95 | // * have an ClassExpression or BinaryExpression and a right
|
---|
| 96 | // of kind ClassExpression as a initializer
|
---|
| 97 | if (ts.isVariableStatement(currentStatement) &&
|
---|
| 98 | currentStatement.declarationList.declarations.length === 1) {
|
---|
| 99 | const variableDeclaration = currentStatement.declarationList.declarations[0];
|
---|
| 100 | const initializer = variableDeclaration.initializer;
|
---|
| 101 | if (ts.isIdentifier(variableDeclaration.name)) {
|
---|
| 102 | const name = variableDeclaration.name.text;
|
---|
| 103 | if (!initializer) {
|
---|
| 104 | const iife = findEnumIife(name, statements[oIndex + 1]);
|
---|
| 105 | if (iife) {
|
---|
| 106 | // update IIFE and replace variable statement and old IIFE
|
---|
| 107 | oldStatementsLength = 2;
|
---|
| 108 | newStatement = updateEnumIife(nodeFactory, currentStatement, iife[0], iife[1]);
|
---|
| 109 | // skip IIFE statement
|
---|
| 110 | oIndex++;
|
---|
| 111 | }
|
---|
| 112 | }
|
---|
| 113 | else if (ts.isClassExpression(initializer) ||
|
---|
| 114 | (ts.isBinaryExpression(initializer) && ts.isClassExpression(initializer.right))) {
|
---|
| 115 | const classStatements = findStatements(name, statements, oIndex);
|
---|
| 116 | if (!classStatements) {
|
---|
| 117 | continue;
|
---|
| 118 | }
|
---|
| 119 | oldStatementsLength = classStatements.length;
|
---|
| 120 | newStatement = createWrappedClass(nodeFactory, variableDeclaration, classStatements);
|
---|
| 121 | oIndex += classStatements.length - 1;
|
---|
| 122 | }
|
---|
| 123 | }
|
---|
| 124 | }
|
---|
| 125 | else if (ts.isClassDeclaration(currentStatement)) {
|
---|
| 126 | const name = currentStatement.name.text;
|
---|
| 127 | const classStatements = findStatements(name, statements, oIndex);
|
---|
| 128 | if (!classStatements) {
|
---|
| 129 | continue;
|
---|
| 130 | }
|
---|
| 131 | oldStatementsLength = classStatements.length;
|
---|
| 132 | newStatement = createWrappedClass(nodeFactory, currentStatement, classStatements);
|
---|
| 133 | oIndex += oldStatementsLength - 1;
|
---|
| 134 | }
|
---|
| 135 | if (newStatement && newStatement.length > 0) {
|
---|
| 136 | if (!updatedStatements) {
|
---|
| 137 | updatedStatements = [...statements];
|
---|
| 138 | }
|
---|
| 139 | updatedStatements.splice(uIndex, oldStatementsLength, ...newStatement);
|
---|
| 140 | // When having more than a single new statement
|
---|
| 141 | // we need to update the update Index
|
---|
| 142 | uIndex += newStatement ? newStatement.length - 1 : 0;
|
---|
| 143 | }
|
---|
| 144 | const result = ts.visitNode(currentStatement, visitor);
|
---|
| 145 | if (result !== currentStatement) {
|
---|
| 146 | if (!updatedStatements) {
|
---|
| 147 | updatedStatements = statements.slice();
|
---|
| 148 | }
|
---|
| 149 | updatedStatements[uIndex] = result;
|
---|
| 150 | }
|
---|
| 151 | }
|
---|
| 152 | // if changes, return updated statements
|
---|
| 153 | // otherwise, return original array instance
|
---|
| 154 | return updatedStatements ? nodeFactory.createNodeArray(updatedStatements) : statements;
|
---|
| 155 | }
|
---|
| 156 | // TS 2.3 enums have statements that are inside a IIFE.
|
---|
| 157 | function findEnumIife(name, statement) {
|
---|
| 158 | if (!ts.isExpressionStatement(statement)) {
|
---|
| 159 | return null;
|
---|
| 160 | }
|
---|
| 161 | const expression = statement.expression;
|
---|
| 162 | if (!expression || !ts.isCallExpression(expression) || expression.arguments.length !== 1) {
|
---|
| 163 | return null;
|
---|
| 164 | }
|
---|
| 165 | const callExpression = expression;
|
---|
| 166 | let exportExpression;
|
---|
| 167 | if (!ts.isParenthesizedExpression(callExpression.expression)) {
|
---|
| 168 | return null;
|
---|
| 169 | }
|
---|
| 170 | const functionExpression = callExpression.expression.expression;
|
---|
| 171 | if (!ts.isFunctionExpression(functionExpression)) {
|
---|
| 172 | return null;
|
---|
| 173 | }
|
---|
| 174 | // The name of the parameter can be different than the name of the enum if it was renamed
|
---|
| 175 | // due to scope hoisting.
|
---|
| 176 | const parameter = functionExpression.parameters[0];
|
---|
| 177 | if (!ts.isIdentifier(parameter.name)) {
|
---|
| 178 | return null;
|
---|
| 179 | }
|
---|
| 180 | const parameterName = parameter.name.text;
|
---|
| 181 | let argument = callExpression.arguments[0];
|
---|
| 182 | if (!ts.isBinaryExpression(argument) ||
|
---|
| 183 | !ts.isIdentifier(argument.left) ||
|
---|
| 184 | argument.left.text !== name) {
|
---|
| 185 | return null;
|
---|
| 186 | }
|
---|
| 187 | let potentialExport = false;
|
---|
| 188 | if (argument.operatorToken.kind === ts.SyntaxKind.FirstAssignment) {
|
---|
| 189 | if (ts.isBinaryExpression(argument.right) &&
|
---|
| 190 | argument.right.operatorToken.kind !== ts.SyntaxKind.BarBarToken) {
|
---|
| 191 | return null;
|
---|
| 192 | }
|
---|
| 193 | potentialExport = true;
|
---|
| 194 | argument = argument.right;
|
---|
| 195 | }
|
---|
| 196 | if (!ts.isBinaryExpression(argument)) {
|
---|
| 197 | return null;
|
---|
| 198 | }
|
---|
| 199 | if (argument.operatorToken.kind !== ts.SyntaxKind.BarBarToken) {
|
---|
| 200 | return null;
|
---|
| 201 | }
|
---|
| 202 | if (potentialExport && !ts.isIdentifier(argument.left)) {
|
---|
| 203 | exportExpression = argument.left;
|
---|
| 204 | }
|
---|
| 205 | // Go through all the statements and check that all match the name
|
---|
| 206 | for (const statement of functionExpression.body.statements) {
|
---|
| 207 | if (!ts.isExpressionStatement(statement) ||
|
---|
| 208 | !ts.isBinaryExpression(statement.expression) ||
|
---|
| 209 | !ts.isElementAccessExpression(statement.expression.left)) {
|
---|
| 210 | return null;
|
---|
| 211 | }
|
---|
| 212 | const leftExpression = statement.expression.left.expression;
|
---|
| 213 | if (!ts.isIdentifier(leftExpression) || leftExpression.text !== parameterName) {
|
---|
| 214 | return null;
|
---|
| 215 | }
|
---|
| 216 | }
|
---|
| 217 | return [callExpression, exportExpression];
|
---|
| 218 | }
|
---|
| 219 | function updateHostNode(nodeFactory, hostNode, expression) {
|
---|
| 220 | // Update existing host node with the pure comment before the variable declaration initializer.
|
---|
| 221 | const variableDeclaration = hostNode.declarationList.declarations[0];
|
---|
| 222 | const outerVarStmt = nodeFactory.updateVariableStatement(hostNode, hostNode.modifiers, nodeFactory.updateVariableDeclarationList(hostNode.declarationList, [
|
---|
| 223 | nodeFactory.updateVariableDeclaration(variableDeclaration, variableDeclaration.name, variableDeclaration.exclamationToken, variableDeclaration.type, expression),
|
---|
| 224 | ]));
|
---|
| 225 | return outerVarStmt;
|
---|
| 226 | }
|
---|
| 227 | /**
|
---|
| 228 | * Find enums, class expression or declaration statements.
|
---|
| 229 | *
|
---|
| 230 | * The classExpressions block to wrap in an iife must
|
---|
| 231 | * - end with an ExpressionStatement
|
---|
| 232 | * - it's expression must be a BinaryExpression
|
---|
| 233 | * - have the same name
|
---|
| 234 | *
|
---|
| 235 | * ```
|
---|
| 236 | let Foo = class Foo {};
|
---|
| 237 | Foo = __decorate([]);
|
---|
| 238 | ```
|
---|
| 239 | */
|
---|
| 240 | function findStatements(name, statements, statementIndex, offset = 0) {
|
---|
| 241 | let count = 1;
|
---|
| 242 | for (let index = statementIndex + 1; index < statements.length; ++index) {
|
---|
| 243 | const statement = statements[index];
|
---|
| 244 | if (!ts.isExpressionStatement(statement)) {
|
---|
| 245 | break;
|
---|
| 246 | }
|
---|
| 247 | const expression = statement.expression;
|
---|
| 248 | if (ts.isCallExpression(expression)) {
|
---|
| 249 | // Ex:
|
---|
| 250 | // setClassMetadata(FooClass, [{}], void 0);
|
---|
| 251 | // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
|
---|
| 252 | // __decorate([propDecorator()], FooClass, "propertyName", void 0);
|
---|
| 253 | // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
|
---|
| 254 | const args = expression.arguments;
|
---|
| 255 | if (args.length > 2) {
|
---|
| 256 | const isReferenced = args.some((arg) => {
|
---|
| 257 | const potentialIdentifier = ts.isPropertyAccessExpression(arg) ? arg.expression : arg;
|
---|
| 258 | return ts.isIdentifier(potentialIdentifier) && potentialIdentifier.text === name;
|
---|
| 259 | });
|
---|
| 260 | if (isReferenced) {
|
---|
| 261 | count++;
|
---|
| 262 | continue;
|
---|
| 263 | }
|
---|
| 264 | }
|
---|
| 265 | }
|
---|
| 266 | else if (ts.isBinaryExpression(expression)) {
|
---|
| 267 | const node = ts.isBinaryExpression(expression.left) ? expression.left.left : expression.left;
|
---|
| 268 | const leftExpression = ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)
|
---|
| 269 | ? // Static Properties // Ex: Foo.bar = 'value';
|
---|
| 270 | // ENUM Property // Ex: ChangeDetectionStrategy[ChangeDetectionStrategy.Default] = "Default";
|
---|
| 271 | node.expression
|
---|
| 272 | : // Ex: FooClass = __decorate([Component()], FooClass);
|
---|
| 273 | node;
|
---|
| 274 | if (ts.isIdentifier(leftExpression) && leftExpression.text === name) {
|
---|
| 275 | count++;
|
---|
| 276 | continue;
|
---|
| 277 | }
|
---|
| 278 | }
|
---|
| 279 | break;
|
---|
| 280 | }
|
---|
| 281 | if (count > 1) {
|
---|
| 282 | return statements.slice(statementIndex + offset, statementIndex + count);
|
---|
| 283 | }
|
---|
| 284 | return undefined;
|
---|
| 285 | }
|
---|
| 286 | function updateEnumIife(nodeFactory, hostNode, iife, exportAssignment) {
|
---|
| 287 | if (!ts.isParenthesizedExpression(iife.expression) ||
|
---|
| 288 | !ts.isFunctionExpression(iife.expression.expression)) {
|
---|
| 289 | throw new Error('Invalid IIFE Structure');
|
---|
| 290 | }
|
---|
| 291 | // Ignore export assignment if variable is directly exported
|
---|
| 292 | if (hostNode.modifiers &&
|
---|
| 293 | hostNode.modifiers.findIndex((m) => m.kind == ts.SyntaxKind.ExportKeyword) != -1) {
|
---|
| 294 | exportAssignment = undefined;
|
---|
| 295 | }
|
---|
| 296 | const expression = iife.expression.expression;
|
---|
| 297 | const updatedFunction = nodeFactory.updateFunctionExpression(expression, expression.modifiers, expression.asteriskToken, expression.name, expression.typeParameters, expression.parameters, expression.type, nodeFactory.updateBlock(expression.body, [
|
---|
| 298 | ...expression.body.statements,
|
---|
| 299 | nodeFactory.createReturnStatement(expression.parameters[0].name),
|
---|
| 300 | ]));
|
---|
| 301 | let arg = nodeFactory.createObjectLiteralExpression();
|
---|
| 302 | if (exportAssignment) {
|
---|
| 303 | arg = nodeFactory.createBinaryExpression(exportAssignment, ts.SyntaxKind.BarBarToken, arg);
|
---|
| 304 | }
|
---|
| 305 | const updatedIife = nodeFactory.updateCallExpression(iife, nodeFactory.updateParenthesizedExpression(iife.expression, updatedFunction), iife.typeArguments, [arg]);
|
---|
| 306 | let value = ast_utils_1.addPureComment(updatedIife);
|
---|
| 307 | if (exportAssignment) {
|
---|
| 308 | value = nodeFactory.createBinaryExpression(exportAssignment, ts.SyntaxKind.FirstAssignment, updatedIife);
|
---|
| 309 | }
|
---|
| 310 | return [updateHostNode(nodeFactory, hostNode, value)];
|
---|
| 311 | }
|
---|
| 312 | function createWrappedClass(nodeFactory, hostNode, statements) {
|
---|
| 313 | const name = hostNode.name.text;
|
---|
| 314 | const updatedStatements = [...statements];
|
---|
| 315 | if (ts.isClassDeclaration(hostNode)) {
|
---|
| 316 | updatedStatements[0] = nodeFactory.createClassDeclaration(hostNode.decorators, undefined, hostNode.name, hostNode.typeParameters, hostNode.heritageClauses, hostNode.members);
|
---|
| 317 | }
|
---|
| 318 | const pureIife = ast_utils_1.addPureComment(nodeFactory.createImmediatelyInvokedArrowFunction([
|
---|
| 319 | ...updatedStatements,
|
---|
| 320 | nodeFactory.createReturnStatement(nodeFactory.createIdentifier(name)),
|
---|
| 321 | ]));
|
---|
| 322 | const modifiers = hostNode.modifiers;
|
---|
| 323 | const isDefault = !!modifiers && modifiers.some((x) => x.kind === ts.SyntaxKind.DefaultKeyword);
|
---|
| 324 | const newStatement = [];
|
---|
| 325 | newStatement.push(nodeFactory.createVariableStatement(isDefault ? undefined : modifiers, nodeFactory.createVariableDeclarationList([nodeFactory.createVariableDeclaration(name, undefined, undefined, pureIife)], ts.NodeFlags.Let)));
|
---|
| 326 | if (isDefault) {
|
---|
| 327 | newStatement.push(nodeFactory.createExportAssignment(undefined, undefined, false, nodeFactory.createIdentifier(name)));
|
---|
| 328 | }
|
---|
| 329 | return newStatement;
|
---|
| 330 | }
|
---|