1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import type {Node, TransformerFactory} from 'typescript';
17import {lstatSync, readdirSync} from 'fs';
18import {join, resolve} from 'path';
19
20import type {IOptions} from '../configs/IOptions';
21import type {TransformPlugin} from './TransformPlugin';
22import { Extension } from '../common/type';
23
24export class TransformerManager {
25  private static readonly sLoadPath: string = join(__dirname, '../', 'transformers');
26
27  private readonly mTransformers: TransformerFactory<Node>[];
28
29  public constructor(options: IOptions) {
30    this.mTransformers = [];
31    this.loadTransformers(options);
32  }
33
34  public getTransformers(): TransformerFactory<Node>[] {
35    return this.mTransformers;
36  }
37
38  private loadTransformers(options: IOptions): void {
39    let subFiles: string[] = readdirSync(TransformerManager.sLoadPath);
40    let plugins: TransformPlugin[] = [];
41    for (const subFile of subFiles) {
42      let subPath: string = resolve(TransformerManager.sLoadPath + '/' + subFile);
43      let isDir: boolean = lstatSync(subPath)?.isDirectory();
44      if (!isDir) {
45        continue;
46      }
47
48      let subDir: string[] = readdirSync(subPath);
49      for (const file of subDir) {
50        if (!file.endsWith(Extension.TS)) {
51          continue;
52        }
53        const fileNameNoSuffix = file.lastIndexOf(Extension.DTS) > -1 ? file.slice(0, file.lastIndexOf(Extension.DTS)) :
54          file.slice(0, file.lastIndexOf(Extension.TS));
55        let path: string = join(subPath, fileNameNoSuffix);
56        let module = require(path);
57        let plugin: TransformPlugin = module?.transformerPlugin;
58        if (plugin) {
59          plugins.push(plugin as TransformPlugin);
60        }
61      }
62    }
63
64    plugins.sort((plugin1: TransformPlugin, plugin2: TransformPlugin) => {
65      return plugin1.order - plugin2.order;
66    });
67
68    plugins.forEach((plugin: TransformPlugin) => {
69      let transformerFactory: TransformerFactory<Node> = plugin?.createTransformerFactory(options);
70      let name: string = plugin?.name;
71      if (transformerFactory && name) {
72        this.mTransformers.push(transformerFactory);
73      }
74    });
75  }
76}
77