private _visitClassDeclaration()

in src/cdk/schematics/update-tool/component-resource-collector.ts [56:171]


  private _visitClassDeclaration(node: ts.ClassDeclaration) {
    if (!node.decorators || !node.decorators.length) {
      return;
    }

    const ngDecorators = getAngularDecorators(this.typeChecker, node.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 = 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 = 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 = getPropertyNameText(property.name);

      if (propertyName === 'styles' && ts.isArrayLiteralExpression(property.initializer)) {
        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;
            this.resolvedStylesheets.push({
              filePath,
              container: node,
              content: el.text,
              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)) {
            const stylesheetPath = this._fileSystem.resolve(sourceFileDirPath, el.text);
            const stylesheet = this.resolveExternalStylesheet(stylesheetPath, node);

            if (stylesheet) {
              this.resolvedStylesheets.push(stylesheet);
            }
          }
        });
      }

      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 = this._fileSystem.read(templatePath);

        if (fileContent) {
          const lineStartsMap = computeLineStartsMap(fileContent);

          this.resolvedTemplates.push({
            filePath: templatePath,
            container: node,
            content: fileContent,
            inline: false,
            start: 0,
            getCharacterAndLineOfPosition: p => getLineAndCharacterFromPosition(lineStartsMap, p),
          });
        }
      }
    });
  }