1import chalk from 'chalk';
2import path from 'path';
3
4import { VERSIONED_RN_IOS_DIR } from '../../../Constants';
5
6export type TransformConfig = {
7  pipeline: TransformPipeline;
8  targetPath: string;
9  input: string;
10};
11
12export type TransformPattern = {
13  paths?: string | string[];
14  replace: RegExp | string;
15  with: string;
16};
17
18export type TransformPipeline = {
19  logHeader?: (filePath: string) => void;
20  transforms: TransformPattern[];
21};
22
23export async function runTransformPipelineAsync({ pipeline, targetPath, input }: TransformConfig) {
24  let output = input;
25  const matches: { value: string; line: number; replacedWith: string }[] = [];
26
27  if (!Array.isArray(pipeline.transforms)) {
28    throw new Error("Pipeline's transformations must be an array of transformation patterns.");
29  }
30
31  pipeline.transforms
32    .filter((transform) => pathMatchesTransformPaths(targetPath, transform.paths))
33    .forEach((transform) => {
34      output = output.replace(transform.replace, (match, ...args) => {
35        const { leftContext } = RegExp as unknown as { leftContext: string };
36        const result = transform.with.replace(/\$[1-9]/g, (m) => args[parseInt(m[1], 10) - 1]);
37
38        matches.push({
39          value: match,
40          line: leftContext.split(/\n/g).length,
41          replacedWith: result,
42        });
43
44        return result;
45      });
46    });
47
48  if (matches.length > 0) {
49    if (pipeline.logHeader) {
50      pipeline.logHeader(path.relative(VERSIONED_RN_IOS_DIR, targetPath));
51    }
52
53    for (const match of matches) {
54      console.log(
55        `${chalk.gray(String(match.line))}:`,
56        chalk.red('-'),
57        chalk.red(match.value.trimRight())
58      );
59      console.log(
60        `${chalk.gray(String(match.line))}:`,
61        chalk.green('+'),
62        chalk.green(match.replacedWith.trimRight())
63      );
64    }
65    console.log();
66  }
67
68  return output;
69}
70
71function pathMatchesTransformPaths(filePath: string, transformPaths?: string | string[]): boolean {
72  if (typeof transformPaths === 'string') {
73    return filePath.includes(transformPaths);
74  }
75  if (Array.isArray(transformPaths)) {
76    return transformPaths.some((transformPath) => filePath.includes(transformPath));
77  }
78  return true;
79}
80