All files / builder/library add-declaration-metadata.service.ts

100% Statements 49/49
100% Branches 22/22
100% Functions 10/10
100% Lines 46/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113        1x 1x 1x   1x         1x 1x   1x 2x           1x     1x 1x     17x     17x             17x 17x 15x 15x   64x 36x     15x 10x   5x     5x   5x             17x     17x 17x 15x 15x   64x 36x     15x 12x   3x       17x           8x 8x 8x 21x 21x 8x 8x         8x 8x         8x     8x      
import type {
  R3ComponentMetadata,
  R3DirectiveMetadata,
} from '@angular/compiler';
import { createCssSelectorForTs } from 'cyia-code-util';
import { Inject, Injectable } from 'static-injector';
import ts from 'typescript';
import { MiniProgramCompilerService } from '../mini-program-compiler';
import {
  LIBRARY_COMPONENT_OUTPUT_PATH_SUFFIX,
  LIBRARY_DIRECTIVE_LISTENERS_SUFFIX,
  LIBRARY_DIRECTIVE_PROPERTIES_SUFFIX,
} from './const';
import { getComponentOutputPath } from './get-library-path';
import { ENTRY_POINT_TOKEN } from './token';
 
@Injectable()
export class AddDeclarationMetaDataService {
  private directiveMap: Map<ts.ClassDeclaration, R3DirectiveMetadata>;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private componentMap: Map<ts.ClassDeclaration, R3ComponentMetadata<any>>;
 
  constructor(
    @Inject(ENTRY_POINT_TOKEN) private entryPoint: string,
    miniProgramCompilerService: MiniProgramCompilerService
  ) {
    this.directiveMap = miniProgramCompilerService.getDirectiveMap();
    this.componentMap = miniProgramCompilerService.getComponentMap();
  }
  run(dTsFileName: string, data: string): string {
    const list = createCssSelectorForTs(data).queryAll(
      `ClassDeclaration`
    ) as ts.ClassDeclaration[];
    return (
      data +
      this.addComponentMetaDataDeclaration(list) +
      this.addDirectiveMetaDataDeclaration(list)
    );
  }
  private addComponentMetaDataDeclaration(list: ts.ClassDeclaration[]) {
    const metaList = ['\n'];
    for (let i = 0; i < list.length; i++) {
      const classDeclaration = list[i];
      const isComponentClassDeclaration = classDeclaration.members.some(
        (item) =>
          ts.isPropertyDeclaration(item) &&
          item.modifiers?.some((modifier) => modifier.getText() === 'static') &&
          item.name.getText() === 'ɵcmp'
      );
      if (!isComponentClassDeclaration) {
        continue;
      }
      metaList.push(
        ...this.getPropertyAndListener(classDeclaration, this.componentMap)
      );
      const className = classDeclaration.name!.getText();
 
      metaList.push(
        `declare const ${className}_${LIBRARY_COMPONENT_OUTPUT_PATH_SUFFIX}:"${getComponentOutputPath(
          this.entryPoint,
          className
        )}";`
      );
    }
    return metaList.join('\n');
  }
  private addDirectiveMetaDataDeclaration(list: ts.ClassDeclaration[]) {
    const metaList = ['\n'];
    for (let i = 0; i < list.length; i++) {
      const classDeclaration = list[i];
      const isDirectiveClassDeclaration = classDeclaration.members.some(
        (item) =>
          ts.isPropertyDeclaration(item) &&
          item.modifiers?.some((modifier) => modifier.getText() === 'static') &&
          item.name.getText() === 'ɵdir'
      );
      if (!isDirectiveClassDeclaration) {
        continue;
      }
      metaList.push(
        ...this.getPropertyAndListener(classDeclaration, this.directiveMap)
      );
    }
    return metaList.join('\n');
  }
  private getPropertyAndListener(
    classDeclaration: ts.ClassDeclaration,
    map: Map<ts.ClassDeclaration, R3DirectiveMetadata>
  ) {
    const className: string = classDeclaration.name!.getText();
    const list: string[] = [];
    for (const [key, meta] of map.entries()) {
      const directiveClassName = meta.name;
      if (directiveClassName === className) {
        const listeners = meta.host.listeners as Record<string, string>;
        list.push(
          `declare const ${className}_${LIBRARY_DIRECTIVE_LISTENERS_SUFFIX}:${JSON.stringify(
            Object.keys(listeners)
          )};`
        );
        const properties = meta.host.properties as Record<string, string>;
        list.push(
          `declare const ${className}_${LIBRARY_DIRECTIVE_PROPERTIES_SUFFIX}:${JSON.stringify(
            Object.keys(properties)
          )};`
        );
        break;
      }
    }
    return list;
  }
}