@angular-devkit/core#join TypeScript Examples

The following examples show how to use @angular-devkit/core#join. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async writeFile(path: string, content: string | Buffer): Promise<void> {
    this.host
      .scopedSync()
      .write(
        normalize(path),
        typeof content === 'string' ? Buffer.from(content) : content
      );

    this.watcherNotifier?.notify([
      { path: getSystemPath(join(this.host.root(), path)), type: 'modified' },
    ]);
  }
Example #2
Source File: output-template-metadata.service.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
private getLibraryTemplate() {
    if (!Object.keys(this.dataGroup.otherMetaCollectionGroup).length) {
      return '';
    }
    const obj: Record<string, ExtraTemplateData> = {};
    for (const key in this.dataGroup.otherMetaCollectionGroup) {
      if (
        Object.prototype.hasOwnProperty.call(
          this.dataGroup.otherMetaCollectionGroup,
          key
        )
      ) {
        const element = this.dataGroup.otherMetaCollectionGroup[key];
        const templateStr = element.templateList
          .map((item) => item.content)
          .join('');

        const useComponents = getUseComponents(
          Array.from(element.libraryPath),
          Array.from(element.localPath),
          this.entryPoint
        );
        const extraTemplateData: ExtraTemplateData = {
          template: templateStr,
          useComponents: useComponents,
        };
        obj[key] = extraTemplateData;
      }
    }
    return `let library_${GLOBAL_TEMPLATE_SUFFIX}=${JSON.stringify(obj)}`;
  }
Example #3
Source File: output-template-metadata.service.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
private getSelfTemplate() {
    const selfMetaCollection = this.dataGroup.otherMetaCollectionGroup['$self'];
    if (!selfMetaCollection) {
      return '';
    }
    this.selfMetaCollection = selfMetaCollection;
    const templateStr = selfMetaCollection.templateList
      .map((item) => item.content)
      .join('');

    const extraTemplateData: ExtraTemplateData = {
      template: templateStr,
      outputPath: resolve(
        normalize('/'),
        join(normalize(LIBRARY_OUTPUT_ROOTDIR), this.entryPoint, 'self')
      ),
    };

    delete this.dataGroup.otherMetaCollectionGroup['$self'];

    return `let $self_${GLOBAL_TEMPLATE_SUFFIX}=${JSON.stringify(
      extraTemplateData
    )}`;
  }
Example #4
Source File: merge-using-component-path.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
export function getUseComponents(
  libraryPath: UseComponent[],
  localPath: UseComponent[],
  moduleId: string
) {
  const list = [...libraryPath];
  list.push(
    ...localPath.map((item) => {
      item.path = getComponentOutputPath(moduleId, item.className);
      return item;
    })
  );
  return list.reduce((pre, cur) => {
    pre[cur.selector] = resolve(
      normalize('/'),
      join(normalize(LIBRARY_OUTPUT_ROOTDIR), cur.path)
    );
    return pre;
  }, {} as Record<string, string>);
}
Example #5
Source File: find-module.ts    From router with MIT License 6 votes vote down vote up
/**
 * Function to find the "closest" module to a generated file's path.
 */
export function findModule(host: Tree, generateDir: string): Path {
  let dir: DirEntry | null = host.getDir('/' + generateDir);

  const moduleRe = /\.module\.ts$/;
  const routingModuleRe = /-routing\.module\.ts/;

  while (dir) {
    const matches = dir.subfiles.filter(
      (p) => moduleRe.test(p) && !routingModuleRe.test(p)
    );

    if (matches.length === 1) {
      return join(dir.path, matches[0]);
    } else if (matches.length > 1) {
      throw new Error(
        'More than one module matches. Use skip-import option to skip importing ' +
          'the component into the closest module.'
      );
    }

    dir = dir.parent;
  }

  throw new Error(
    'Could not find an NgModule. Use the skip-import ' +
      'option to skip importing in NgModule.'
  );
}
Example #6
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async getFileList(dirPath: Path): Promise<string[]> {
    const fileList: string[] = [];
    const list = await this.list(dirPath).toPromise();
    for (let i = 0; i < list.length; i++) {
      const element = list[i];
      const filePath = join(dirPath, element);
      if (await this.isDirectory(filePath).toPromise()) {
        fileList.push(...(await this.getFileList(filePath)));
      } else {
        fileList.push(filePath);
      }
    }
    return fileList;
  }
Example #7
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async moveDir(list: string[], from: string, to: string) {
    for (let i = 0; i < list.length; i++) {
      const item = list[i];
      await this.rename(
        normalize(join(this.root(), 'src', from, item)),
        normalize(join(this.root(), 'src', to, item))
      ).toPromise();
    }
  }
Example #8
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async addPageEntry(list: string[]) {
    const configPath = join(normalize(this.root()), 'src', 'app.json');
    const file = await this.read(configPath).toPromise();
    const json = JSON.parse(fileBufferToString(file));
    const entryList = list.map((item) => `pages/${item}/${item}-entry`);
    json.pages = entryList;
    await this.write(
      configPath,
      stringToFileBuffer(JSON.stringify(json))
    ).toPromise();
  }
Example #9
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async addSpecEntry(list: string[]) {
    const configPath = join(normalize(this.root()), 'src', 'app.json');
    const file = await this.read(configPath).toPromise();
    const json = JSON.parse(fileBufferToString(file));
    const entryList = list.map((item) => `spec/${item}/${item}-entry`);
    json.pages = entryList;
    await this.write(
      configPath,
      stringToFileBuffer(JSON.stringify(json))
    ).toPromise();
  }
Example #10
Source File: builder.prod.spec.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
describeBuilder(runBuilder, BROWSER_BUILDER_INFO, (harness) => {
  describe('builder-prod', () => {
    it('运行', async () => {
      const root = harness.host.root();
      const list = await harness.host.getFileList(
        normalize(join(root, 'src', '__pages'))
      );
      list.push(
        ...(await harness.host.getFileList(
          normalize(join(root, 'src', '__components'))
        ))
      );
      await harness.host.importPathRename(list);
      await harness.host.moveDir(ALL_PAGE_NAME_LIST, '__pages', 'pages');
      await harness.host.moveDir(
        ALL_COMPONENT_NAME_LIST,
        '__components',
        'components'
      );
      await harness.host.addPageEntry(ALL_PAGE_NAME_LIST);
      harness.useTarget('build', angularConfig);
      const result = await harness.executeOnce();
      expect(result).toBeTruthy();
      expect(result.error).toBeFalsy();
      expect(result.logs[0].level !== 'error').toBeTruthy();
      expect(result.result?.success).toBeTruthy();
    });
  });
});
Example #11
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async writeFiles(files: Record<string, string | Buffer>): Promise<void> {
    const watchEvents = this.watcherNotifier
      ? ([] as { path: string; type: 'modified' | 'deleted' }[])
      : undefined;

    for (const [path, content] of Object.entries(files)) {
      this.host
        .scopedSync()
        .write(
          normalize(path),
          typeof content === 'string' ? Buffer.from(content) : content
        );

      watchEvents?.push({
        path: getSystemPath(join(this.host.root(), path)),
        type: 'modified',
      });
    }

    if (watchEvents) {
      this.watcherNotifier?.notify(watchEvents);
    }
  }
Example #12
Source File: index.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
async modifyFile(
    path: string,
    modifier: (content: string) => string | Promise<string>
  ): Promise<void> {
    const content = this.readFile(path);
    await this.writeFile(path, await modifier(content));

    this.watcherNotifier?.notify([
      { path: getSystemPath(join(this.host.root(), path)), type: 'modified' },
    ]);
  }
Example #13
Source File: get-angular-sub-dir.rule.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
export function getAngularSubDirRuleFactory(options: HookOptions): Rule {
  return async (tree: Tree, context: SchematicContext) => {
    const dirs = tree.getDir(
      join(normalize(options.sourceInSchematicsPath), options.subDir)
    );
    if (dirs.subdirs.length && dirs.subfiles.length) {
      return;
    }
    await cloneSpecifiedDir(options);
  };
}
Example #14
Source File: const.ts    From angular-miniprogram with MIT License 6 votes vote down vote up
SCHEMATICS_FORMS_LIBRARY_HOOK_FILE_LIST = [
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/default_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/checkbox_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/number_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/radio_control_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/range_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/select_control_value_accessor.ts'
  ),
  join(
    normalize(SCHEMATICS_FORMS_LIBRARY_PATH),
    'src/directives/select_multiple_control_value_accessor.ts'
  ),
  join(normalize(SCHEMATICS_FORMS_LIBRARY_PATH), 'src/directives.ts'),
  join(normalize(SCHEMATICS_FORMS_LIBRARY_PATH), 'src/forms.ts'),
]
Example #15
Source File: find-module.ts    From edit-in-place with MIT License 6 votes vote down vote up
/**
 * Function to find the "closest" module to a generated file's path.
 */
export function findModule(
  host: Tree,
  generateDir: string,
  moduleExt = MODULE_EXT,
  routingModuleExt = ROUTING_MODULE_EXT
): Path {
  let dir: DirEntry | null = host.getDir('/' + generateDir);
  let foundRoutingModule = false;

  while (dir) {
    const allMatches = dir.subfiles.filter(p => p.endsWith(moduleExt));
    const filteredMatches = allMatches.filter(p => !p.endsWith(routingModuleExt));

    foundRoutingModule = foundRoutingModule || allMatches.length !== filteredMatches.length;

    if (filteredMatches.length === 1) {
      return join(dir.path, filteredMatches[0]);
    } else if (filteredMatches.length > 1) {
      throw new Error(
        'More than one module matches. Use skip-import option to skip importing ' +
          'the component into the closest module.'
      );
    }

    dir = dir.parent;
  }

  const errorMsg = foundRoutingModule
    ? 'Could not find a non Routing NgModule.' +
      `\nModules with suffix '${routingModuleExt}' are strictly reserved for routing.` +
      '\nUse the skip-import option to skip importing in NgModule.'
    : 'Could not find an NgModule. Use the skip-import option to skip importing in NgModule.';
  throw new Error(errorMsg);
}
Example #16
Source File: library.spec.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
describeBuilder(execute, LIBRARY_BUILDER_INFO, (harness) => {
  describe('test-library', () => {
    it('运行', async () => {
      harness.useTarget('library', DEFAULT_ANGULAR_LIBRARY_CONFIG);
      const result = await harness.executeOnce();
      expect(result).toBeTruthy();
      expect(result.result).toBeTruthy();
      expect(result.result.success).toBeTruthy();
      if (!result.result.success) {
        console.error(result.result.error);
      }
      const workspaceRoot: string = (result.result as any).workspaceRoot;
      const outputPath = normalize(`dist/test-library`);
      const output = path.join(workspaceRoot, outputPath);
      const entryFile = harness.expectFile(
        join(outputPath, 'esm2020', 'test-library.mjs')
      );
      entryFile.toExist();
      entryFile.content.toContain(`$self_Global_Template`);
      const globalSelfTemplate = harness.expectFile(
        join(
          outputPath,
          'esm2020',
          'global-self-template',
          'global-self-template.component.mjs'
        )
      );
      globalSelfTemplate.toExist();
      globalSelfTemplate.content.toContain(
        `GlobalSelfTemplateComponent_${LIBRARY_COMPONENT_METADATA_SUFFIX}`
      );
      fs.copySync(
        output,
        path.resolve(
          process.cwd(),
          'test',
          'hello-world-app',
          'node_modules',
          'test-library'
        )
      );
    });
  });
});
Example #17
Source File: index.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
async removeFile(path: string): Promise<void> {
    this.host.scopedSync().delete(normalize(path));

    this.watcherNotifier?.notify([
      { path: getSystemPath(join(this.host.root(), path)), type: 'deleted' },
    ]);
  }
Example #18
Source File: setup-component-data.service.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
run(
    data: string,
    originFileName: string,
    customStyleSheetProcessor: CustomStyleSheetProcessor
  ) {
    const changedData = changeComponent(data);
    if (!changedData) {
      return data;
    }
    const useComponentPath =
      this.dataGroup.useComponentPath.get(originFileName)!;
    const componentClassName = changedData.componentName;
    const componentDirName = strings.dasherize(
      strings.camelize(componentClassName)
    );
    const libraryPath = getComponentOutputPath(
      this.entryPoint,
      componentClassName
    );
    const styleUrlList = this.dataGroup.style.get(originFileName);
    const styleContentList: string[] = [];
    styleUrlList?.forEach((item) => {
      styleContentList.push(customStyleSheetProcessor.styleMap.get(item)!);
    });
    const selfTemplateImportStr = this.dataGroup.otherMetaCollectionGroup[
      '$self'
    ]
      ? `<import src="${resolve(
          normalize('/'),
          join(
            normalize(LIBRARY_OUTPUT_ROOTDIR),
            this.entryPoint,
            'self' + this.buildPlatform.fileExtname.contentTemplate
          )
        )}"/>`
      : '';

    const insertComponentData: ExportLibraryComponentMeta = {
      id:
        strings.classify(this.entryPoint) +
        strings.classify(strings.camelize(componentDirName)),
      className: componentClassName,
      content:
        selfTemplateImportStr +
        this.dataGroup.outputContent.get(originFileName)!,
      libraryPath: libraryPath,
      useComponents: {
        ...getUseComponents(
          useComponentPath.libraryPath,
          useComponentPath.localPath,
          this.entryPoint
        ),
        ...this.addGlobalTemplateService.getSelfUseComponents(),
      },
      moduleId: this.entryPoint,
    };
    if (styleContentList.length) {
      insertComponentData.style = styleContentList.join('\n');
    }

    return `${
      changedData.content
    }\nlet ${componentClassName}_${LIBRARY_COMPONENT_METADATA_SUFFIX}=${JSON.stringify(
      insertComponentData
    )}`;
  }
Example #19
Source File: index.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
workspaceRoot = join(normalize(__dirname), `../hello-world-app/`)
Example #20
Source File: get-library-path.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
export function getComponentOutputPath(entry: string, className: string) {
  return join(
    normalize(entry),
    dasherize(camelize(className)),
    dasherize(camelize(className))
  );
}
Example #21
Source File: builder.spec.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
describeBuilder(runBuilder, BROWSER_BUILDER_INFO, (harness) => {
  describe('builder-dev', () => {
    for (const platform of [
      PlatformType.wx,
      PlatformType.bdzn,
      PlatformType.dd,
      PlatformType.jd,
      PlatformType.qq,
      PlatformType.zfb,
      PlatformType.zj,
    ]) {
      it(`运行${PlatformType[platform]}`, async () => {
        angularConfig.platform = platform;
        const root = harness.host.root();
        const list = await harness.host.getFileList(
          normalize(join(root, 'src', '__pages'))
        );
        list.push(
          ...(await harness.host.getFileList(
            normalize(join(root, 'src', '__components'))
          ))
        );
        await harness.host.importPathRename(list);
        await harness.host.moveDir(ALL_PAGE_NAME_LIST, '__pages', 'pages');
        await harness.host.moveDir(
          ALL_COMPONENT_NAME_LIST,
          '__components',
          'components'
        );
        await harness.host.addPageEntry(ALL_PAGE_NAME_LIST);
        harness.useTarget('build', angularConfig);
        const result = await harness.executeOnce();
        expect(result).toBeTruthy();
        expect(result.error).toBeFalsy();
        expect(result.logs[0].level !== 'error').toBeTruthy();
        expect(result.result?.success).toBeTruthy();
        const injectList = getBuildPlatformInjectConfig(angularConfig.platform);
        const injector = Injector.create({ providers: injectList });
        const buildPlatform = injector.get(BuildPlatform);
        harness
          .expectFile(
            join(
              normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
              `app${buildPlatform.fileExtname.style}`
            )
          )
          .toExist();
        const libraryPath = join(
          normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
          LIBRARY_OUTPUT_ROOTDIR,
          'test-library'
        );
        const librarySelfTemplateFile = harness.expectFile(
          join(libraryPath, `self${buildPlatform.fileExtname.contentTemplate}`)
        );
        librarySelfTemplateFile.toExist();
        librarySelfTemplateFile.content.toContain(`$$mp$$__self__$$`);
        TEST_LIBRARY_COMPONENT_LIST.forEach((item) => {
          const componentPath = join(libraryPath, item, item);
          harness
            .expectFile(componentPath + buildPlatform.fileExtname.logic)
            .toExist();
          harness
            .expectFile(
              componentPath + (buildPlatform.fileExtname.config || '.json')
            )
            .toExist();
          harness
            .expectFile(componentPath + buildPlatform.fileExtname.content)
            .toExist();
        });
        const realTestPath: string = result.result?.outputPath as string;
        const appTestPath = path.resolve(process.cwd(), '__test-app');
        fs.copySync(realTestPath, path.resolve(process.cwd(), '__test-app'));
        // ('等待断点放开');
        fs.removeSync(appTestPath);
      });
    }
  });
});
Example #22
Source File: dynamic-library-entry.plugin.ts    From angular-miniprogram with MIT License 5 votes vote down vote up
apply(compiler: webpack.Compiler) {
    compiler.hooks.thisCompilation.tap(
      'DynamicLibraryEntryPlugin',
      (thisCompilation) => {
        (thisCompilation as any)[LibrarySymbol] = (thisCompilation as any)[
          LibrarySymbol
        ] || { buildPlatform: this.buildPlatform };
        const hooks = webpack.NormalModule.getCompilationHooks(thisCompilation);
        hooks.readResource
          .for(CUSTOM_URI)
          .tapAsync(
            'DynamicLibraryEntryPlugin',
            (loaderContext: any, callback) => {
              const resourcePath: string = loaderContext.resourcePath;
              const id = resourcePath.match(CUSTOM_URI_REG)![1];
              const libraryMeta = this.libraryComponentMap.get(id);

              callback(
                undefined,
                `
            import * as amp from 'angular-miniprogram';
            import * as library from '${libraryMeta?.contextPath}';
            amp.componentRegistry(library.${libraryMeta?.className});
            `
              );
              return;
            }
          );
        compiler.hooks.finishMake.tapAsync(
          'DynamicLibraryEntryPlugin',
          (compilation, callback) => {
            const libraryLoaderContext: LibraryLoaderContext = (
              compilation as any
            )[LibrarySymbol];
            if (compilation !== thisCompilation) {
              callback(undefined);
              return;
            }
            if (libraryLoaderContext.libraryMetaList) {
              libraryLoaderContext.libraryMetaList.forEach((item) => {
                this.libraryComponentMap.set(item.id, item);
              });
            }

            if (this.libraryComponentMap.size === 0) {
              callback(undefined);
              return;
            }
            let j = 0;
            this.libraryComponentMap.forEach((meta) => {
              const entry = join(
                normalize(LIBRARY_OUTPUT_ROOTDIR),
                meta.libraryPath
              );
              const dep = webpack.EntryPlugin.createDependency(
                `${CUSTOM_URI}://${path.join('__license', meta.id)}.ts`,
                entry
              );
              compilation.addEntry(
                compiler.context,
                dep,
                entry,
                (err, result) => {
                  j++;
                  if (j === this.libraryComponentMap.size) {
                    callback(undefined);
                  }
                }
              );
            });
          }
        );
      }
    );
  }
Example #23
Source File: find-module.ts    From edit-in-place with MIT License 5 votes vote down vote up
/**
 * Find the module referred by a set of options passed to the schematics.
 */
export function findModuleFromOptions(host: Tree, options: any, projectPath: any): Path | undefined {
  if (options.hasOwnProperty('skipImport') && options.skipImport) {
    return undefined;
  }

  const moduleExt = options.moduleExt || MODULE_EXT;
  const routingModuleExt = options.routingModuleExt || ROUTING_MODULE_EXT;

  if (!options.module) {
    const pathToCheck = (projectPath || '') + '/' + options.name;
    const module = findModule(host, pathToCheck, moduleExt, routingModuleExt);
    return module ? normalize(module) : undefined;
  } else {
    const modulePath = normalize(`/${projectPath}/${options.module}`);
    const componentPath = normalize(`/${projectPath}/${options.name}`);
    const moduleBaseName = normalize(modulePath)
      .split('/')
      .pop();

    const candidateSet = new Set<Path>([normalize(projectPath || '/')]);

    for (let dir = modulePath; dir !== NormalizedRoot; dir = dirname(dir)) {
      candidateSet.add(dir);
    }
    for (let dir = componentPath; dir !== NormalizedRoot; dir = dirname(dir)) {
      candidateSet.add(dir);
    }

    const candidatesDirs = [...candidateSet].sort((a, b) => b.length - a.length);
    for (const c of candidatesDirs) {
      const candidateFiles = ['', `${moduleBaseName}.ts`, `${moduleBaseName}${moduleExt}`].map(x => join(c, x));

      for (const sc of candidateFiles) {
        if (host.exists(sc)) {
          return normalize(sc);
        }
      }
    }
    throw new Error(
      `Specified module '${options.module}' does not exist.\n` +
        `Looked in the following directories:\n    ${candidatesDirs.join('\n    ')}`
    );
  }
}
Example #24
Source File: compile-source-files.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
export async function compileSourceFiles(
  graph: BuildGraph,
  tsConfig: ParsedConfiguration,
  moduleResolutionCache: ts.ModuleResolutionCache,
  extraOptions?: Partial<CompilerOptions>,
  stylesheetProcessor?: StylesheetProcessor,
  ngccProcessor?: NgccProcessor,
  watch?: boolean
) {
  const { NgtscProgram, formatDiagnostics } = await ngCompilerCli();

  const tsConfigOptions: CompilerOptions = {
    ...tsConfig.options,
    ...extraOptions,
  };
  const entryPoint: EntryPointNode = graph.find(
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    isEntryPointInProgress() as any
  )!;
  const ngPackageNode: PackageNode = graph.find(isPackage)!;
  const inlineStyleLanguage = ngPackageNode.data.inlineStyleLanguage;

  const tsCompilerHost = ngccTransformCompilerHost(
    cacheCompilerHost(
      graph,
      entryPoint,
      tsConfigOptions,
      moduleResolutionCache,
      stylesheetProcessor,
      inlineStyleLanguage
    ),
    tsConfigOptions,
    ngccProcessor!,
    moduleResolutionCache
  );
  // inject
  augmentLibraryMetadata(tsCompilerHost);
  const cache = entryPoint.cache;
  const sourceFileCache = cache.sourcesFileCache;

  // Create the Angular specific program that contains the Angular compiler
  const angularProgram = new NgtscProgram(
    tsConfig.rootNames,
    tsConfigOptions,
    tsCompilerHost,
    cache.oldNgtscProgram
  );

  const angularCompiler = angularProgram.compiler;
  const { ignoreForDiagnostics, ignoreForEmit } = angularCompiler;

  // SourceFile versions are required for builder programs.
  // The wrapped host inside NgtscProgram adds additional files that will not have versions.
  const typeScriptProgram = angularProgram.getTsProgram();
  augmentProgramWithVersioning(typeScriptProgram);

  let builder: ts.BuilderProgram | ts.EmitAndSemanticDiagnosticsBuilderProgram;
  if (watch) {
    builder = cache.oldBuilder =
      ts.createEmitAndSemanticDiagnosticsBuilderProgram(
        typeScriptProgram,
        tsCompilerHost,
        cache.oldBuilder
      );
    cache.oldNgtscProgram = angularProgram;
  } else {
    // When not in watch mode, the startup cost of the incremental analysis can be avoided by
    // using an abstract builder that only wraps a TypeScript program.
    builder = ts.createAbstractBuilder(typeScriptProgram, tsCompilerHost);
  }

  // Update semantic diagnostics cache
  const affectedFiles = new Set<ts.SourceFile>();

  // Analyze affected files when in watch mode for incremental type checking
  if ('getSemanticDiagnosticsOfNextAffectedFile' in builder) {
    // eslint-disable-next-line no-constant-condition
    while (true) {
      const result = builder.getSemanticDiagnosticsOfNextAffectedFile(
        undefined,
        (sourceFile) => {
          // If the affected file is a TTC shim, add the shim's original source file.
          // This ensures that changes that affect TTC are typechecked even when the changes
          // are otherwise unrelated from a TS perspective and do not result in Ivy codegen changes.
          // For example, changing @Input property types of a directive used in another component's
          // template.
          if (
            ignoreForDiagnostics.has(sourceFile) &&
            sourceFile.fileName.endsWith('.ngtypecheck.ts')
          ) {
            // This file name conversion relies on internal compiler logic and should be converted
            // to an official method when available. 15 is length of `.ngtypecheck.ts`
            const originalFilename = sourceFile.fileName.slice(0, -15) + '.ts';
            const originalSourceFile = builder.getSourceFile(originalFilename);
            if (originalSourceFile) {
              affectedFiles.add(originalSourceFile);
            }

            return true;
          }

          return false;
        }
      );

      if (!result) {
        break;
      }

      affectedFiles.add(result.affected as ts.SourceFile);
    }
  }

  // Collect program level diagnostics
  const allDiagnostics: ts.Diagnostic[] = [
    ...angularCompiler.getOptionDiagnostics(),
    ...builder.getOptionsDiagnostics(),
    ...builder.getGlobalDiagnostics(),
  ];
  // inject
  let injector = Injector.create({
    providers: [
      ...getBuildPlatformInjectConfig(PlatformType.library),
      {
        provide: MiniProgramCompilerService,
        useFactory: (injector: Injector, buildPlatform: BuildPlatform) => {
          return new MiniProgramCompilerService(
            angularProgram,
            injector,
            buildPlatform
          );
        },
        deps: [Injector, BuildPlatform],
      },
      {
        provide: ENTRY_FILE_TOKEN,
        useValue: join(
          dirname(normalize(tsConfig.rootNames[0])),
          normalize(tsConfigOptions.flatModuleOutFile!)
        ),
      },
      {
        provide: ENTRY_POINT_TOKEN,
        useValue: entryPoint.data.entryPoint.moduleId,
      },
    ],
  });
  const miniProgramCompilerService = injector.get(MiniProgramCompilerService);
  // Required to support asynchronous resource loading
  // Must be done before creating transformers or getting template diagnostics
  await angularCompiler.analyzeAsync();
  // inject
  miniProgramCompilerService.init();
  const metaMap =
    await miniProgramCompilerService.exportComponentBuildMetaMap();
  injector = Injector.create({
    parent: injector,
    providers: [
      { provide: RESOLVED_DATA_GROUP_TOKEN, useValue: metaMap },
      { provide: AddDeclarationMetaDataService },
      { provide: OutputTemplateMetadataService },
      { provide: SetupComponentDataService },
    ],
  });
  // Collect source file specific diagnostics
  for (const sourceFile of builder.getSourceFiles()) {
    if (!ignoreForDiagnostics.has(sourceFile)) {
      allDiagnostics.push(
        ...builder.getSyntacticDiagnostics(sourceFile),
        ...builder.getSemanticDiagnostics(sourceFile)
      );
    }

    if (sourceFile.isDeclarationFile) {
      continue;
    }

    // Collect sources that are required to be emitted
    if (
      !ignoreForEmit.has(sourceFile) &&
      !angularCompiler.incrementalDriver.safeToSkipEmit(sourceFile)
    ) {
      // If required to emit, diagnostics may have also changed
      if (!ignoreForDiagnostics.has(sourceFile)) {
        affectedFiles.add(sourceFile);
      }
    } else if (
      sourceFileCache &&
      !affectedFiles.has(sourceFile) &&
      !ignoreForDiagnostics.has(sourceFile)
    ) {
      // Use cached Angular diagnostics for unchanged and unaffected files
      const angularDiagnostics =
        sourceFileCache.getAngularDiagnostics(sourceFile);
      if (angularDiagnostics?.length) {
        allDiagnostics.push(...angularDiagnostics);
      }
    }
  }

  // Collect new Angular diagnostics for files affected by changes
  for (const affectedFile of affectedFiles) {
    const angularDiagnostics = angularCompiler.getDiagnosticsForFile(
      affectedFile,
      /** OptimizeFor.WholeProgram */ 1
    );

    allDiagnostics.push(...angularDiagnostics);
    sourceFileCache.updateAngularDiagnostics(affectedFile, angularDiagnostics);
  }

  const otherDiagnostics = [];
  const errorDiagnostics = [];
  for (const diagnostic of allDiagnostics) {
    if (diagnostic.category === ts.DiagnosticCategory.Error) {
      errorDiagnostics.push(diagnostic);
    } else {
      otherDiagnostics.push(diagnostic);
    }
  }

  if (otherDiagnostics.length) {
    log.msg(formatDiagnostics(errorDiagnostics));
  }

  if (errorDiagnostics.length) {
    throw new Error(formatDiagnostics(errorDiagnostics));
  }

  const transformers = angularCompiler.prepareEmit().transformers;
  for (const sourceFile of builder.getSourceFiles()) {
    if (!ignoreForEmit.has(sourceFile)) {
      builder.emit(sourceFile, undefined, undefined, undefined, transformers);
    }
  }
  function augmentLibraryMetadata(compilerHost: ts.CompilerHost) {
    const oldWriteFile = compilerHost.writeFile;
    compilerHost.writeFile = function (
      fileName: string,
      data: string,
      writeByteOrderMark,
      onError,
      sourceFiles
    ) {
      const entryFileName = injector.get(ENTRY_FILE_TOKEN);
      if (fileName.endsWith('.map')) {
        return oldWriteFile.call(
          this,
          fileName,
          data,
          writeByteOrderMark,
          onError,
          sourceFiles
        );
      }
      if (fileName.endsWith('.d.ts')) {
        const service = injector.get(AddDeclarationMetaDataService);
        const result = service.run(fileName, data);
        return oldWriteFile.call(
          this,
          fileName,
          result,
          writeByteOrderMark,
          onError,
          sourceFiles
        );
      }
      const sourceFile = sourceFiles && sourceFiles[0];
      if (sourceFile) {
        if (
          entryFileName ===
          normalize(sourceFile.fileName.replace(/\.ts$/, '.js'))
        ) {
          const service = injector.get(OutputTemplateMetadataService);
          const result = service.run(fileName, data, sourceFiles![0]);
          return oldWriteFile.call(
            this,
            fileName,
            result,
            writeByteOrderMark,
            onError,
            sourceFiles
          );
        }
        const originFileName = path.normalize(sourceFile.fileName);
        const setupComponentDataService = injector.get(
          SetupComponentDataService
        );
        const result = setupComponentDataService.run(
          data,
          originFileName,
          stylesheetProcessor! as CustomStyleSheetProcessor
        );
        return oldWriteFile.call(
          this,
          fileName,
          result,
          writeByteOrderMark,
          onError,
          sourceFiles
        );
      }
      return oldWriteFile.call(
        this,
        fileName,
        data,
        writeByteOrderMark,
        onError,
        sourceFiles
      );
    };
  }
}
Example #25
Source File: index.spec.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
describeBuilder(runBuilder, KARMA_BUILDER_INFO, (harness) => {
  // 此测试仅能本地使用,并且只能一个测试用例单独开启
  xdescribe('karma', () => {
    it('运行', async () => {
      const root = harness.host.root();

      await harness.host.addSpecEntry([
        'empty',
        'tag-view-convert-spec',
        'style-class-spec',
        'life-time-spec',
        'ng-if-spec',
        'http-spec',
        'ng-content-spec',
        'ng-for-spec',
        'ng-library-import-spec',
        'ng-switch-spec',
        'ng-template-outlet-spec',
        'self-template-spec',
      ]);
      harness.useTarget('build', angularConfig);
      let appTestPath: string;
      const result = new Promise<BuilderHarnessExecutionResult<BuilderOutput>>(
        (res) => {
          let result;
          harness
            .execute({
              testContext: {
                buildSuccess: async (webpackConfig) => {
                  const realTestPath: string = webpackConfig.output!
                    .path as string;
                  appTestPath = path.resolve(process.cwd(), '__test-app');
                  fs.removeSync(appTestPath);
                  fs.copySync(realTestPath, appTestPath);
                },
              },
            })
            .subscribe({
              next: (value) => (result = value),
              complete: () => res(result),
            });
        }
      );
      await result;
      expect((await result).error).toBe(undefined);
      expect((await result).result.success).toBe(true);
      fs.removeSync(appTestPath);
    });

    xit('watch', async () => {
      const root = harness.host.root();
      const list: string[] = [];

      list.push(
        ...(await harness.host.getFileList(
          normalize(join(root, 'src', '__components'))
        )),
        ...(await harness.host.getFileList(
          normalize(join(root, 'src', 'spec'))
        ))
      );
      await harness.host.importPathRename(list);
      await harness.host.moveDir(
        ['component1', 'component2'],
        '__components',
        'components'
      );
      await harness.host.addSpecEntry(['base-component']);
      harness.useTarget('build', { ...angularConfig, watch: true });
      let appTestPath: string;
      const result = new Promise<BuilderHarnessExecutionResult<BuilderOutput>>(
        (res) => {
          let first = true;
          harness
            .execute({
              testContext: {
                buildSuccess: async (webpackConfig) => {
                  const realTestPath: string = webpackConfig.output!
                    .path as string;
                  appTestPath = path.resolve(process.cwd(), '__test-app');
                  if (!first) {
                    fs.removeSync(appTestPath);
                    fs.copySync(realTestPath, appTestPath);
                    return;
                  }
                  first = false;
                  fs.removeSync(appTestPath);
                  fs.copySync(realTestPath, appTestPath);
                  setTimeout(async () => {
                    await writeFile();
                  }, 0);
                },
              },
            })
            .subscribe({
              next: (value) => res(value),
            });
        }
      );
      await result;
      expect((await result).error).toBe(undefined);
      expect((await result).result.success).toBe(true);
      fs.removeSync(appTestPath);
    });
  });

  function writeFile() {
    const fileContent = harness.readFile(
      'src/spec/base-component/base-component.entry.spec.ts'
    );

    return harness.writeFiles({
      'src/spec/base-component/base-component.entry.spec.ts': `${fileContent}
      describe('test-add',()=>{it('main',()=>{expect(true).toBe(true)})});`,
    });
  }
});
Example #26
Source File: index.origin.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
/**
 * @experimental Direct usage of this function is considered experimental.
 */
export function execute(
  options: KarmaBuilderOptions,
  context: BuilderContext,
  transforms: {
    webpackConfiguration?: ExecutionTransformer<Configuration>;
    // The karma options transform cannot be async without a refactor of the builder implementation
    karmaOptions?: (options: KarmaConfigOptions) => KarmaConfigOptions;
  } = {}
): Observable<BuilderOutput> {
  // Check Angular version.
  assertCompatibleAngularVersion(context.workspaceRoot);

  let singleRun: boolean | undefined;
  if (options.watch !== undefined) {
    singleRun = !options.watch;
  }

  return from(
    initialize(options, context, transforms.webpackConfiguration)
  ).pipe(
    switchMap(async ([karma, webpackConfig]) => {
      const karmaOptions: KarmaConfigOptions = {
        singleRun,
      };

      // Convert browsers from a string to an array
      if (options.browsers) {
        karmaOptions.browsers = options.browsers.split(',');
      }

      if (options.reporters) {
        // Split along commas to make it more natural, and remove empty strings.
        const reporters = options.reporters
          .reduce<string[]>((acc, curr) => acc.concat(curr.split(',')), [])
          .filter((x) => !!x);

        if (reporters.length > 0) {
          karmaOptions.reporters = reporters;
        }
      }

      // prepend special webpack loader that will transform test.ts
      if (options.include && options.include.length > 0) {
        const mainFilePath = getSystemPath(
          join(normalize(context.workspaceRoot), options.main)
        );
        const files = findTests(
          options.include,
          dirname(mainFilePath),
          context.workspaceRoot
        );
        // early exit, no reason to start karma
        if (!files.length) {
          throw new Error(
            `Specified patterns: "${options.include.join(
              ', '
            )}" did not match any spec files.`
          );
        }

        // Get the rules and ensure the Webpack configuration is setup properly
        const rules = webpackConfig.module?.rules || [];
        if (!webpackConfig.module) {
          webpackConfig.module = { rules };
        } else if (!webpackConfig.module.rules) {
          webpackConfig.module.rules = rules;
        }

        rules.unshift({
          test: mainFilePath,
          use: {
            // cannot be a simple path as it differs between environments
            loader: SingleTestTransformLoader,
            options: {
              files,
              logger: context.logger,
            },
          },
        });
      }

      karmaOptions.buildWebpack = {
        options,
        webpackConfig,
        logger: context.logger,
      };

      const config = await karma.config.parseConfig(
        resolve(context.workspaceRoot, options.karmaConfig),
        transforms.karmaOptions
          ? transforms.karmaOptions(karmaOptions)
          : karmaOptions,
        { promiseConfig: true, throwErrors: true }
      );

      return [karma, config] as [typeof karma, KarmaConfigOptions];
    }),
    switchMap(
      ([karma, karmaConfig]) =>
        new Observable<BuilderOutput>((subscriber) => {
          // Pass onto Karma to emit BuildEvents.
          karmaConfig.buildWebpack ??= {};
          if (typeof karmaConfig.buildWebpack === 'object') {
            (karmaConfig.buildWebpack as any).failureCb ??= () =>
              subscriber.next({ success: false });
            (karmaConfig.buildWebpack as any).successCb ??= () =>
              subscriber.next({ success: true });
            (karmaConfig.buildWebpack as any).testContext = (
              context as any
            ).testContext;
          }

          // Complete the observable once the Karma server returns.
          const karmaServer = new karma.Server(
            karmaConfig as Config,
            (exitCode) => {
              subscriber.next({ success: exitCode === 0 });
              subscriber.complete();
            }
          );

          const karmaStart = karmaServer.start();

          // Cleanup, signal Karma to exit.
          return () => karmaStart.then(() => karmaServer.stop());
        })
    ),
    defaultIfEmpty({ success: false })
  );
}
Example #27
Source File: builder.watch.spec.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
describeBuilder(
  runBuilder,
  { ...BROWSER_BUILDER_INFO, name: 'test-builder:watch' },
  (harness) => {
    describe('builder-watch-dev', () => {
      it('运行', async () => {
        const root = harness.host.root();
        const list = await harness.host.getFileList(
          normalize(join(root, 'src', '__pages'))
        );
        list.push(
          ...(await harness.host.getFileList(
            normalize(join(root, 'src', '__components'))
          ))
        );
        await harness.host.importPathRename(list);
        await harness.host.moveDir(ALL_PAGE_NAME_LIST, '__pages', 'pages');
        await harness.host.moveDir(
          ALL_COMPONENT_NAME_LIST,
          '__components',
          'components'
        );
        await harness.host.addPageEntry(ALL_PAGE_NAME_LIST);
        let finish: Function;
        const waitFinish = new Promise((res) => {
          finish = res;
        });
        harness.useTarget('build', angularConfig);
        harness
          .execute()
          .pipe(
            concatMap((result, index) => {
              if (index) {
                return of(result);
              }
              harness
                .writeFiles({
                  'src/pages/sub3/sub3.component.html': `<p>{{title}} works!</p>`,
                  'src/pages/sub3/sub3.component.ts': `import { Component } from '@angular/core';
              
              @Component({
                selector: 'app-sub3',
                templateUrl: './sub3.component.html',
              })
              export class Sub3Component {
                title = 'sub3组件';
               
              }
              `,
                  'src/pages/sub3/sub3.entry.json': `{
                "usingComponents": { }
              }
              `,
                  'src/pages/sub3/sub3.entry.ts': `import { pageStartup } from 'angular-miniprogram';
              import { Sub3Component } from './sub3.component';
              import { Sub3Module } from './sub3.module';
              
              pageStartup(Sub3Module, Sub3Component);
              `,
                  'src/pages/sub3/sub3.module.ts': `import { NgModule } from '@angular/core';
              import { Sub3Component } from './sub3.component';
              
              @NgModule({
                declarations: [Sub3Component],
              })
              export class Sub3Module {}
              `,
                })
                .then(
                  (res) => {},
                  (rej) => {
                    throw rej;
                  }
                );
              return of(result);
            }),
            take(2),
            skip(1)
          )
          .subscribe((result) => {
            expect(result.logs[0].level !== 'error').toBeTruthy();
            expect(result).toBeTruthy();
            expect(result.error).toBeFalsy();
            expect(result.result?.success).toBeTruthy();
            expect(result.logs[0].message).toContain('sub3-entry.js');
            harness
              .expectFile(
                join(
                  normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
                  'pages/sub3/sub3-entry.js'
                )
              )
              .toExist();
            harness
              .expectFile(
                join(
                  normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
                  'pages/sub3/sub3-entry.json'
                )
              )
              .toExist();
            harness
              .expectFile(
                join(
                  normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
                  'pages/sub3/sub3-entry.wxml'
                )
              )
              .toExist();
            harness
              .expectFile(
                join(
                  normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
                  'pages/sub3/sub3-entry.wxss'
                )
              )
              .toExist();
            harness
              .expectFile(
                join(
                  normalize(DEFAULT_ANGULAR_CONFIG.outputPath),
                  'library/test-library/lib-comp1-component/lib-comp1-component.js'
                )
              )
              .toExist();
            finish();
          });
        await waitFinish;
      });
    });
  }
);
Example #28
Source File: index.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
execute(
    options: Partial<BuilderHarnessExecutionOptions> = {}
  ): Observable<BuilderHarnessExecutionResult> {
    const {
      configuration,
      outputLogsOnException = true,
      outputLogsOnFailure = true,
      useNativeFileWatching = false,
    } = options;

    const targetOptions = {
      ...this.options.get(null),
      ...((configuration && this.options.get(configuration)) ?? {}),
    };

    if (!useNativeFileWatching) {
      if (this.watcherNotifier) {
        throw new Error('Only one harness execution at a time is supported.');
      }
      this.watcherNotifier = new WatcherNotifier();
    }

    const contextHost: ContextHost = {
      findBuilderByTarget: async (project, target) => {
        this.validateProjectName(project);
        if (target === this.targetName) {
          return {
            info: this.builderInfo,
            handler: this.builderHandler as BuilderHandlerFn<json.JsonObject>,
          };
        }

        const builderTarget = this.builderTargets.get(target);
        if (builderTarget) {
          return { info: builderTarget.info, handler: builderTarget.handler };
        }

        throw new Error('Project target does not exist.');
      },
      async getBuilderName(project, target) {
        return (await this.findBuilderByTarget(project, target)).info
          .builderName;
      },
      getMetadata: async (project) => {
        this.validateProjectName(project);

        return this.projectMetadata as json.JsonObject;
      },
      getOptions: async (project, target, configuration) => {
        this.validateProjectName(project);
        if (target === this.targetName) {
          return this.options.get(configuration ?? null) ?? {};
        } else if (configuration !== undefined) {
          // Harness builder targets currently do not support configurations
          return {};
        } else {
          return (
            (this.builderTargets.get(target)?.options as json.JsonObject) || {}
          );
        }
      },
      hasTarget: async (project, target) => {
        this.validateProjectName(project);

        return this.targetName === target || this.builderTargets.has(target);
      },
      getDefaultConfigurationName: async (_project, _target) => {
        return undefined;
      },
      validate: async (options, builderName) => {
        let schema;
        if (builderName === this.builderInfo.builderName) {
          schema = this.builderInfo.optionSchema;
        } else {
          for (const [, value] of this.builderTargets) {
            if (value.info.builderName === builderName) {
              schema = value.info.optionSchema;
              break;
            }
          }
        }

        const validator = await this.schemaRegistry
          .compile(schema ?? true)
          .toPromise();
        const { data } = await validator(options).toPromise();

        return data as json.JsonObject;
      },
    };
    const context = new HarnessBuilderContext(
      this.builderInfo,
      getSystemPath(this.host.root()),
      contextHost,
      useNativeFileWatching ? undefined : this.watcherNotifier,
      options.testContext
    );
    if (this.targetName !== undefined) {
      context.target = {
        project: this.projectName,
        target: this.targetName,
        configuration: configuration as string,
      };
    }

    const logs: logging.LogEntry[] = [];
    context.logger.subscribe((e) => logs.push(e));

    return this.schemaRegistry.compile(this.builderInfo.optionSchema).pipe(
      mergeMap((validator) => validator(targetOptions as any)),
      map((validationResult) => validationResult.data),
      mergeMap((data) =>
        convertBuilderOutputToObservable(
          this.builderHandler(data as T & json.JsonObject, context)
        )
      ),
      map((buildResult) => ({ result: buildResult, error: undefined })),
      catchError((error) => {
        if (outputLogsOnException) {
          // eslint-disable-next-line no-console
          console.error(logs.map((entry) => entry.message).join('\n'));
          // eslint-disable-next-line no-console
          console.error(error);
        }

        return of({ result: undefined, error });
      }),
      map(({ result, error }) => {
        if (
          outputLogsOnFailure &&
          result?.success === false &&
          logs.length > 0
        ) {
          // eslint-disable-next-line no-console
          console.error(logs.map((entry) => entry.message).join('\n'));
        }

        // Capture current logs and clear for next
        const currentLogs = logs.slice();
        logs.length = 0;

        return { result, error, logs: currentLogs };
      }),
      finalize(() => {
        this.watcherNotifier = undefined;

        for (const teardown of context.teardowns) {
          // eslint-disable-next-line @typescript-eslint/no-floating-promises
          teardown();
        }
      })
    );
  }
Example #29
Source File: mini-program-application-analysis.service.ts    From angular-miniprogram with MIT License 4 votes vote down vote up
async exportComponentBuildMetaMap() {
    const injector = Injector.create({
      providers: [
        {
          provide: MiniProgramCompilerService,
          useFactory: (injector: Injector, buildPlatform: BuildPlatform) => {
            return new MiniProgramCompilerService(
              this.ngTscProgram,
              injector,
              buildPlatform
            );
          },
          deps: [Injector, BuildPlatform],
        },
      ],
      parent: this.injector,
    });
    const miniProgramCompilerService = injector.get(MiniProgramCompilerService);
    miniProgramCompilerService.init();
    const metaMap =
      await miniProgramCompilerService.exportComponentBuildMetaMap();

    const selfMetaCollection = metaMap.otherMetaCollectionGroup['$self'];
    const selfTemplate: Record<string, string> = {};
    if (selfMetaCollection) {
      const importSelfTemplatePath = `/self-template/self${this.buildPlatform.fileExtname.contentTemplate}`;
      const importSelfTemplate = `<import src="${importSelfTemplatePath}"/>`;
      metaMap.outputContent.forEach((value, key) => {
        value = `${importSelfTemplate}${value}`;
        metaMap.outputContent.set(key, value);
      });

      metaMap.useComponentPath.forEach((value, key) => {
        value.libraryPath.push(...selfMetaCollection.libraryPath);
        value.localPath.push(...selfMetaCollection.localPath);
      });
      selfTemplate[importSelfTemplatePath] = selfMetaCollection.templateList
        .map((item) => item.content)
        .join('');
      delete metaMap.otherMetaCollectionGroup['$self'];
    }
    metaMap.useComponentPath.forEach((value, key) => {
      value.libraryPath = Array.from(new Set(value.libraryPath));
      value.localPath = Array.from(new Set(value.localPath));
    });
    const styleMap = new Map<string, string[]>();
    metaMap.style.forEach((value, key) => {
      const entryPattern = this.getComponentPagePattern(key);
      styleMap.set(entryPattern.outputFiles.style, value);
    });
    const contentMap = new Map<string, string>();
    metaMap.outputContent.forEach((value, key) => {
      const entryPattern = this.getComponentPagePattern(key);
      contentMap.set(entryPattern.outputFiles.content, value);
    });

    metaMap.style = styleMap;
    const config = new Map<
      string,
      {
        usingComponents: { selector: string; path: string }[];
        existConfig: string;
      }
    >();
    metaMap.useComponentPath.forEach((value, key) => {
      const entryPattern = this.getComponentPagePattern(key);
      const list = [
        ...value.libraryPath.map((item) => {
          item.path = resolve(
            normalize('/'),
            join(normalize(LIBRARY_OUTPUT_ROOTDIR), item.path)
          );
          return item;
        }),
      ];
      list.push(
        ...value.localPath.map((item) => ({
          selector: item.selector,
          path: resolve(
            normalize('/'),
            normalize(this.getComponentPagePattern(item.path).outputFiles.path)
          ),
          className: item.className,
        }))
      );
      config.set(entryPattern.outputFiles.config, {
        usingComponents: list,
        existConfig: entryPattern.inputFiles.config,
      });
    });

    for (const key in metaMap.otherMetaCollectionGroup) {
      if (
        Object.prototype.hasOwnProperty.call(
          metaMap.otherMetaCollectionGroup,
          key
        )
      ) {
        const element = metaMap.otherMetaCollectionGroup[key];
        element.libraryPath.forEach((item) => {
          item.path = resolve(
            normalize('/'),
            join(normalize(LIBRARY_OUTPUT_ROOTDIR), item.path)
          );
        });
        element.localPath.forEach((item) => {
          item.path = resolve(
            normalize('/'),
            normalize(this.getComponentPagePattern(item.path).outputFiles.path)
          );
        });
      }
    }
    return {
      style: styleMap,
      outputContent: contentMap,
      config: config,
      otherMetaCollectionGroup: metaMap.otherMetaCollectionGroup,
      selfTemplate,
    };
  }