[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.getResourceUrl = exports.replaceResources = void 0;
|
---|
| 30 | const ts = __importStar(require("typescript"));
|
---|
| 31 | const direct_resource_1 = require("../loaders/direct-resource");
|
---|
| 32 | const inline_resource_1 = require("../loaders/inline-resource");
|
---|
| 33 | function replaceResources(shouldTransform, getTypeChecker, directTemplateLoading = false, inlineStyleMimeType, inlineStyleFileExtension) {
|
---|
| 34 | if (inlineStyleMimeType && !/^text\/[-.\w]+$/.test(inlineStyleMimeType)) {
|
---|
| 35 | throw new Error('Invalid inline style MIME type.');
|
---|
| 36 | }
|
---|
| 37 | return (context) => {
|
---|
| 38 | const typeChecker = getTypeChecker();
|
---|
| 39 | const resourceImportDeclarations = [];
|
---|
| 40 | const moduleKind = context.getCompilerOptions().module;
|
---|
| 41 | const nodeFactory = context.factory;
|
---|
| 42 | const visitNode = (node) => {
|
---|
| 43 | if (ts.isClassDeclaration(node)) {
|
---|
| 44 | const decorators = ts.visitNodes(node.decorators, (node) => ts.isDecorator(node)
|
---|
| 45 | ? visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleMimeType, inlineStyleFileExtension)
|
---|
| 46 | : node);
|
---|
| 47 | return nodeFactory.updateClassDeclaration(node, decorators, node.modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
|
---|
| 48 | }
|
---|
| 49 | return ts.visitEachChild(node, visitNode, context);
|
---|
| 50 | };
|
---|
| 51 | return (sourceFile) => {
|
---|
| 52 | if (!shouldTransform(sourceFile.fileName)) {
|
---|
| 53 | return sourceFile;
|
---|
| 54 | }
|
---|
| 55 | const updatedSourceFile = ts.visitNode(sourceFile, visitNode);
|
---|
| 56 | if (resourceImportDeclarations.length) {
|
---|
| 57 | // Add resource imports
|
---|
| 58 | return context.factory.updateSourceFile(updatedSourceFile, ts.setTextRange(context.factory.createNodeArray([
|
---|
| 59 | ...resourceImportDeclarations,
|
---|
| 60 | ...updatedSourceFile.statements,
|
---|
| 61 | ]), updatedSourceFile.statements));
|
---|
| 62 | }
|
---|
| 63 | return updatedSourceFile;
|
---|
| 64 | };
|
---|
| 65 | };
|
---|
| 66 | }
|
---|
| 67 | exports.replaceResources = replaceResources;
|
---|
| 68 | function visitDecorator(nodeFactory, node, typeChecker, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleMimeType, inlineStyleFileExtension) {
|
---|
| 69 | if (!isComponentDecorator(node, typeChecker)) {
|
---|
| 70 | return node;
|
---|
| 71 | }
|
---|
| 72 | if (!ts.isCallExpression(node.expression)) {
|
---|
| 73 | return node;
|
---|
| 74 | }
|
---|
| 75 | const decoratorFactory = node.expression;
|
---|
| 76 | const args = decoratorFactory.arguments;
|
---|
| 77 | if (args.length !== 1 || !ts.isObjectLiteralExpression(args[0])) {
|
---|
| 78 | // Unsupported component metadata
|
---|
| 79 | return node;
|
---|
| 80 | }
|
---|
| 81 | const objectExpression = args[0];
|
---|
| 82 | const styleReplacements = [];
|
---|
| 83 | // visit all properties
|
---|
| 84 | let properties = ts.visitNodes(objectExpression.properties, (node) => ts.isObjectLiteralElementLike(node)
|
---|
| 85 | ? visitComponentMetadata(nodeFactory, node, styleReplacements, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleMimeType, inlineStyleFileExtension)
|
---|
| 86 | : node);
|
---|
| 87 | // replace properties with updated properties
|
---|
| 88 | if (styleReplacements.length > 0) {
|
---|
| 89 | const styleProperty = nodeFactory.createPropertyAssignment(nodeFactory.createIdentifier('styles'), nodeFactory.createArrayLiteralExpression(styleReplacements));
|
---|
| 90 | properties = nodeFactory.createNodeArray([...properties, styleProperty]);
|
---|
| 91 | }
|
---|
| 92 | return nodeFactory.updateDecorator(node, nodeFactory.updateCallExpression(decoratorFactory, decoratorFactory.expression, decoratorFactory.typeArguments, [nodeFactory.updateObjectLiteralExpression(objectExpression, properties)]));
|
---|
| 93 | }
|
---|
| 94 | function visitComponentMetadata(nodeFactory, node, styleReplacements, directTemplateLoading, resourceImportDeclarations, moduleKind, inlineStyleMimeType, inlineStyleFileExtension) {
|
---|
| 95 | if (!ts.isPropertyAssignment(node) || ts.isComputedPropertyName(node.name)) {
|
---|
| 96 | return node;
|
---|
| 97 | }
|
---|
| 98 | const name = node.name.text;
|
---|
| 99 | switch (name) {
|
---|
| 100 | case 'moduleId':
|
---|
| 101 | return undefined;
|
---|
| 102 | case 'templateUrl':
|
---|
| 103 | const url = getResourceUrl(node.initializer, directTemplateLoading ? `!${direct_resource_1.DirectAngularResourceLoaderPath}!` : '');
|
---|
| 104 | if (!url) {
|
---|
| 105 | return node;
|
---|
| 106 | }
|
---|
| 107 | const importName = createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind);
|
---|
| 108 | if (!importName) {
|
---|
| 109 | return node;
|
---|
| 110 | }
|
---|
| 111 | return nodeFactory.updatePropertyAssignment(node, nodeFactory.createIdentifier('template'), importName);
|
---|
| 112 | case 'styles':
|
---|
| 113 | case 'styleUrls':
|
---|
| 114 | if (!ts.isArrayLiteralExpression(node.initializer)) {
|
---|
| 115 | return node;
|
---|
| 116 | }
|
---|
| 117 | const isInlineStyle = name === 'styles';
|
---|
| 118 | const styles = ts.visitNodes(node.initializer.elements, (node) => {
|
---|
| 119 | if (!ts.isStringLiteral(node) && !ts.isNoSubstitutionTemplateLiteral(node)) {
|
---|
| 120 | return node;
|
---|
| 121 | }
|
---|
| 122 | let url;
|
---|
| 123 | if (isInlineStyle) {
|
---|
| 124 | if (inlineStyleMimeType) {
|
---|
| 125 | const data = Buffer.from(node.text).toString('base64');
|
---|
| 126 | url = `data:${inlineStyleMimeType};charset=utf-8;base64,${data}`;
|
---|
| 127 | }
|
---|
| 128 | else if (inlineStyleFileExtension) {
|
---|
| 129 | const data = Buffer.from(node.text).toString('base64');
|
---|
| 130 | const containingFile = node.getSourceFile().fileName;
|
---|
| 131 | url = `${containingFile}.${inlineStyleFileExtension}!=!${inline_resource_1.InlineAngularResourceLoaderPath}?data=${encodeURIComponent(data)}!${containingFile}`;
|
---|
| 132 | }
|
---|
| 133 | else {
|
---|
| 134 | return nodeFactory.createStringLiteral(node.text);
|
---|
| 135 | }
|
---|
| 136 | }
|
---|
| 137 | else {
|
---|
| 138 | url = getResourceUrl(node);
|
---|
| 139 | }
|
---|
| 140 | if (!url) {
|
---|
| 141 | return node;
|
---|
| 142 | }
|
---|
| 143 | return createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind);
|
---|
| 144 | });
|
---|
| 145 | // Styles should be placed first
|
---|
| 146 | if (isInlineStyle) {
|
---|
| 147 | styleReplacements.unshift(...styles);
|
---|
| 148 | }
|
---|
| 149 | else {
|
---|
| 150 | styleReplacements.push(...styles);
|
---|
| 151 | }
|
---|
| 152 | return undefined;
|
---|
| 153 | default:
|
---|
| 154 | return node;
|
---|
| 155 | }
|
---|
| 156 | }
|
---|
| 157 | function getResourceUrl(node, loader = '') {
|
---|
| 158 | // only analyze strings
|
---|
| 159 | if (!ts.isStringLiteral(node) && !ts.isNoSubstitutionTemplateLiteral(node)) {
|
---|
| 160 | return null;
|
---|
| 161 | }
|
---|
| 162 | return `${loader}${/^\.?\.\//.test(node.text) ? '' : './'}${node.text}`;
|
---|
| 163 | }
|
---|
| 164 | exports.getResourceUrl = getResourceUrl;
|
---|
| 165 | function isComponentDecorator(node, typeChecker) {
|
---|
| 166 | if (!ts.isDecorator(node)) {
|
---|
| 167 | return false;
|
---|
| 168 | }
|
---|
| 169 | const origin = getDecoratorOrigin(node, typeChecker);
|
---|
| 170 | if (origin && origin.module === '@angular/core' && origin.name === 'Component') {
|
---|
| 171 | return true;
|
---|
| 172 | }
|
---|
| 173 | return false;
|
---|
| 174 | }
|
---|
| 175 | function createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind = ts.ModuleKind.ES2015) {
|
---|
| 176 | const urlLiteral = nodeFactory.createStringLiteral(url);
|
---|
| 177 | if (moduleKind < ts.ModuleKind.ES2015) {
|
---|
| 178 | return nodeFactory.createPropertyAccessExpression(nodeFactory.createCallExpression(nodeFactory.createIdentifier('require'), [], [urlLiteral]), 'default');
|
---|
| 179 | }
|
---|
| 180 | else {
|
---|
| 181 | const importName = nodeFactory.createIdentifier(`__NG_CLI_RESOURCE__${resourceImportDeclarations.length}`);
|
---|
| 182 | resourceImportDeclarations.push(nodeFactory.createImportDeclaration(undefined, undefined, nodeFactory.createImportClause(false, importName, undefined), urlLiteral));
|
---|
| 183 | return importName;
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 | function getDecoratorOrigin(decorator, typeChecker) {
|
---|
| 187 | if (!ts.isCallExpression(decorator.expression)) {
|
---|
| 188 | return null;
|
---|
| 189 | }
|
---|
| 190 | let identifier;
|
---|
| 191 | let name = '';
|
---|
| 192 | if (ts.isPropertyAccessExpression(decorator.expression.expression)) {
|
---|
| 193 | identifier = decorator.expression.expression.expression;
|
---|
| 194 | name = decorator.expression.expression.name.text;
|
---|
| 195 | }
|
---|
| 196 | else if (ts.isIdentifier(decorator.expression.expression)) {
|
---|
| 197 | identifier = decorator.expression.expression;
|
---|
| 198 | }
|
---|
| 199 | else {
|
---|
| 200 | return null;
|
---|
| 201 | }
|
---|
| 202 | // NOTE: resolver.getReferencedImportDeclaration would work as well but is internal
|
---|
| 203 | const symbol = typeChecker.getSymbolAtLocation(identifier);
|
---|
| 204 | if (symbol && symbol.declarations && symbol.declarations.length > 0) {
|
---|
| 205 | const declaration = symbol.declarations[0];
|
---|
| 206 | let module;
|
---|
| 207 | if (ts.isImportSpecifier(declaration)) {
|
---|
| 208 | name = (declaration.propertyName || declaration.name).text;
|
---|
| 209 | module = declaration.parent.parent.parent.moduleSpecifier.text;
|
---|
| 210 | }
|
---|
| 211 | else if (ts.isNamespaceImport(declaration)) {
|
---|
| 212 | // Use the name from the decorator namespace property access
|
---|
| 213 | module = declaration.parent.parent.moduleSpecifier.text;
|
---|
| 214 | }
|
---|
| 215 | else if (ts.isImportClause(declaration)) {
|
---|
| 216 | name = declaration.name.text;
|
---|
| 217 | module = declaration.parent.moduleSpecifier.text;
|
---|
| 218 | }
|
---|
| 219 | else {
|
---|
| 220 | return null;
|
---|
| 221 | }
|
---|
| 222 | return { name, module };
|
---|
| 223 | }
|
---|
| 224 | return null;
|
---|
| 225 | }
|
---|