1import fs from 'fs-extra'; 2import minimatch from 'minimatch'; 3import path from 'path'; 4 5import { CopyFileOptions, CopyFileResult, StringTransform } from './Transforms.types'; 6import { arrayize } from './Utils'; 7 8export * from './Transforms.types'; 9 10/** 11 * Transforms input string according to the given transform rules. 12 */ 13export function transformString( 14 input: string, 15 transforms: StringTransform[] | null | undefined 16): string { 17 if (!transforms) { 18 return input; 19 } 20 return transforms.reduce( 21 // @ts-ignore @tsapeta: TS gets crazy on `replaceWith` being a function. 22 (acc, { find, replaceWith }) => acc.replace(find, replaceWith), 23 input 24 ); 25} 26 27/** 28 * Transforms file's content in-place. 29 */ 30export async function transformFileAsync( 31 filePath: string, 32 transforms: StringTransform[] | null | undefined 33): Promise<void> { 34 const content = await fs.readFile(filePath, 'utf8'); 35 await fs.outputFile(filePath, transformString(content, transforms)); 36} 37 38/** 39 * Copies a file from source directory to target directory with transformed relative path and content. 40 */ 41export async function copyFileWithTransformsAsync( 42 options: CopyFileOptions 43): Promise<CopyFileResult> { 44 const { sourceFile, sourceDirectory, targetDirectory, transforms } = options; 45 const sourcePath = path.join(sourceDirectory, sourceFile); 46 47 // Transform the target path according to rename rules. 48 const targetFile = transformString(sourceFile, transforms.path); 49 const targetPath = path.join(targetDirectory, targetFile); 50 51 // Filter out transforms that don't match paths patterns. 52 const filteredContentTransforms = 53 transforms.content?.filter( 54 ({ paths }) => 55 !paths || 56 arrayize(paths).some((pattern) => minimatch(sourceFile, pattern, { matchBase: true })) 57 ) ?? []; 58 59 // Transform source content. 60 const content = transformString(await fs.readFile(sourcePath, 'utf8'), filteredContentTransforms); 61 62 // Save transformed source file at renamed target path. 63 await fs.outputFile(targetPath, content); 64 65 return { 66 content, 67 targetFile, 68 }; 69} 70