123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- "use strict";
- /**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.dev/license
- */
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.ComponentResourceCollector = void 0;
- const path_1 = require("path");
- const ts = require("typescript");
- const decorators_1 = require("./utils/decorators");
- const functions_1 = require("./utils/functions");
- const line_mappings_1 = require("./utils/line-mappings");
- const property_name_1 = require("./utils/property-name");
- /**
- * Collector that can be used to find Angular templates and stylesheets referenced within
- * given TypeScript source files (inline or external referenced files)
- */
- class ComponentResourceCollector {
- constructor(typeChecker, _fileSystem) {
- this.typeChecker = typeChecker;
- this._fileSystem = _fileSystem;
- this.resolvedTemplates = [];
- this.resolvedStylesheets = [];
- }
- visitNode(node) {
- if (node.kind === ts.SyntaxKind.ClassDeclaration) {
- this._visitClassDeclaration(node);
- }
- }
- _visitClassDeclaration(node) {
- const decorators = ts.getDecorators(node);
- if (!decorators || !decorators.length) {
- return;
- }
- const ngDecorators = (0, decorators_1.getAngularDecorators)(this.typeChecker, decorators);
- const componentDecorator = ngDecorators.find(dec => dec.name === 'Component');
- // In case no "@Component" decorator could be found on the current class, skip.
- if (!componentDecorator) {
- return;
- }
- const decoratorCall = componentDecorator.node.expression;
- // In case the component decorator call is not valid, skip this class declaration.
- if (decoratorCall.arguments.length !== 1) {
- return;
- }
- const componentMetadata = (0, functions_1.unwrapExpression)(decoratorCall.arguments[0]);
- // Ensure that the component metadata is an object literal expression.
- if (!ts.isObjectLiteralExpression(componentMetadata)) {
- return;
- }
- const sourceFile = node.getSourceFile();
- const filePath = this._fileSystem.resolve(sourceFile.fileName);
- const sourceFileDirPath = (0, path_1.dirname)(sourceFile.fileName);
- // Walk through all component metadata properties and determine the referenced
- // HTML templates (either external or inline)
- componentMetadata.properties.forEach(property => {
- if (!ts.isPropertyAssignment(property)) {
- return;
- }
- const propertyName = (0, property_name_1.getPropertyNameText)(property.name);
- if (propertyName === 'styles') {
- const elements = ts.isArrayLiteralExpression(property.initializer)
- ? property.initializer.elements
- : [property.initializer];
- elements.forEach(el => {
- if (ts.isStringLiteralLike(el)) {
- // Need to add an offset of one to the start because the template quotes are
- // not part of the template content.
- const templateStartIdx = el.getStart() + 1;
- const content = stripBom(el.text);
- this.resolvedStylesheets.push({
- filePath,
- container: node,
- content,
- inline: true,
- start: templateStartIdx,
- getCharacterAndLineOfPosition: pos => ts.getLineAndCharacterOfPosition(sourceFile, pos + templateStartIdx),
- });
- }
- });
- }
- // In case there is an inline template specified, ensure that the value is statically
- // analyzable by checking if the initializer is a string literal-like node.
- if (propertyName === 'template' && ts.isStringLiteralLike(property.initializer)) {
- // Need to add an offset of one to the start because the template quotes are
- // not part of the template content.
- const templateStartIdx = property.initializer.getStart() + 1;
- this.resolvedTemplates.push({
- filePath,
- container: node,
- content: property.initializer.text,
- inline: true,
- start: templateStartIdx,
- getCharacterAndLineOfPosition: pos => ts.getLineAndCharacterOfPosition(sourceFile, pos + templateStartIdx),
- });
- }
- if (propertyName === 'styleUrls' && ts.isArrayLiteralExpression(property.initializer)) {
- property.initializer.elements.forEach(el => {
- if (ts.isStringLiteralLike(el)) {
- this._trackExternalStylesheet(sourceFileDirPath, el, node);
- }
- });
- }
- if (propertyName === 'styleUrl' && ts.isStringLiteralLike(property.initializer)) {
- this._trackExternalStylesheet(sourceFileDirPath, property.initializer, node);
- }
- if (propertyName === 'templateUrl' && ts.isStringLiteralLike(property.initializer)) {
- const templateUrl = property.initializer.text;
- const templatePath = this._fileSystem.resolve(sourceFileDirPath, templateUrl);
- // In case the template does not exist in the file system, skip this
- // external template.
- if (!this._fileSystem.fileExists(templatePath)) {
- return;
- }
- const fileContent = stripBom(this._fileSystem.read(templatePath) || '');
- if (fileContent) {
- const lineStartsMap = (0, line_mappings_1.computeLineStartsMap)(fileContent);
- this.resolvedTemplates.push({
- filePath: templatePath,
- container: node,
- content: fileContent,
- inline: false,
- start: 0,
- getCharacterAndLineOfPosition: p => (0, line_mappings_1.getLineAndCharacterFromPosition)(lineStartsMap, p),
- });
- }
- }
- });
- }
- /** Resolves an external stylesheet by reading its content and computing line mappings. */
- resolveExternalStylesheet(filePath, container) {
- // Strip the BOM to avoid issues with the Sass compiler. See:
- // https://github.com/angular/components/issues/24227#issuecomment-1200934258
- const fileContent = stripBom(this._fileSystem.read(filePath) || '');
- if (!fileContent) {
- return null;
- }
- const lineStartsMap = (0, line_mappings_1.computeLineStartsMap)(fileContent);
- return {
- filePath: filePath,
- container: container,
- content: fileContent,
- inline: false,
- start: 0,
- getCharacterAndLineOfPosition: pos => (0, line_mappings_1.getLineAndCharacterFromPosition)(lineStartsMap, pos),
- };
- }
- _trackExternalStylesheet(sourceFileDirPath, node, container) {
- const stylesheetPath = this._fileSystem.resolve(sourceFileDirPath, node.text);
- const stylesheet = this.resolveExternalStylesheet(stylesheetPath, container);
- if (stylesheet) {
- this.resolvedStylesheets.push(stylesheet);
- }
- }
- }
- exports.ComponentResourceCollector = ComponentResourceCollector;
- /** Strips the BOM from a string. */
- function stripBom(content) {
- return content.replace(/\uFEFF/g, '');
- }
- //# sourceMappingURL=component-resource-collector.js.map
|