From 7f2f02a62187a03d2a51a874a9093d376d8f6b3f Mon Sep 17 00:00:00 2001 From: wxzhang Date: Sat, 18 Jan 2025 11:24:57 +0800 Subject: [PATCH] feat: add copyDirs/copyFiles option --- src/fs/copyDirs.ts | 79 +++++++++++++++++++++++++++------------------ src/fs/copyFiles.ts | 76 ++++++++++++++++++++++++++----------------- 2 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/fs/copyDirs.ts b/src/fs/copyDirs.ts index 0842cd8..136129c 100644 --- a/src/fs/copyDirs.ts +++ b/src/fs/copyDirs.ts @@ -24,27 +24,58 @@ import { getDynamicValue } from "../misc/getDynamicValue"; export type {CopyFileInfo} from "./copyFiles" export interface CopyDirsOptions { - vars? : Record | ((file: string) => Record | Promise>); // 传递给模板的变量 - pattern? : string; // 匹配的文件或文件夹,支持通配符 - ignore? : string[]; // 忽略的文件或文件夹,支持通配符 - clean? : boolean // 是否清空目标文件夹 - overwrite? : boolean | ((filename: string) => boolean | Promise); // 是否覆盖已存在的文件,可以是boolean或返回boolean的同步/异步函数 - before? : (info:CopyFileInfo) => void | typeof ABORT; // 复制前的回调 - after? : (info:CopyFileInfo) => void | typeof ABORT; // 复制后的回调 - error? : (error:Error,{source,target}:{source: string, target: string})=>void | typeof ABORT // 复制出错的回调 + vars? : Record | ((file: string) => Record | Promise>); // 传递给模板的变量 + pattern? : string; // 匹配的文件或文件夹,支持通配符 + ignore? : string[]; // 忽略的文件或文件夹,支持通配符 + clean? : boolean // 是否清空目标文件夹 + overwrite? : boolean | ((filename: string) => boolean | Promise); // 是否覆盖已存在的文件,可以是boolean或返回boolean的同步/异步函数 + before? : (info:CopyFileInfo) => void | typeof ABORT; // 复制前的回调 + after? : (info:CopyFileInfo) => void | typeof ABORT; // 复制后的回调 + error? : (error:Error,{source,target}:{source: string, target: string})=>void | typeof ABORT // 复制出错的回调 + templateOptions? : Record | ((file: string) => Record | Promise>); } -export async function copyDirs( - srcDir: string, - targetDir: string, - options?: CopyDirsOptions -) { + +async function copyTemplateFile(fileInfo: Required, opts: CopyDirsOptions) { + const targetFile = path.join( + path.dirname(fileInfo.target), + path.basename(fileInfo.target, ".art") + ); + const shouldOverwrite = typeof opts.overwrite === 'function' + ? await Promise.resolve(opts.overwrite(targetFile)) + : opts.overwrite; + if (shouldOverwrite === false && existsSync(targetFile)) { + return; + } + const template = artTemplate(fileInfo.source); + template.defaults.imports.json=(v:any)=>{ + try{ + return JSON.stringify(v,null,4) + }catch{ + return v + } + } + const templateVars = await getDynamicValue.call(opts, opts.vars, [fileInfo.file]); + const templateOptions = await getDynamicValue.call(opts, opts.templateOptions, [fileInfo.file]); + await writeFile(targetFile, template(templateVars, templateOptions), {encoding:"utf-8"}); +} + +async function copyRegularFile(fileInfo: Required, opts: CopyDirsOptions) { + const shouldOverwrite = await getDynamicValue.call(opts, opts.overwrite, [fileInfo.file]) as boolean; + if (shouldOverwrite === false && existsSync(fileInfo.target)) { + return; + } + await copyFile(fileInfo.source, fileInfo.target); +} + + +export async function copyDirs( srcDir: string, targetDir: string, options?: CopyDirsOptions) { const opts = assignObject({ pattern: "**/*.*", ignore:[], clean:false }, options); - const { ignore, pattern,vars={} } = opts; + const { ignore, pattern } = opts; if (!existsSync(srcDir)) throw new Error(`srcDir=${srcDir} not exists`); if (!path.isAbsolute(targetDir)) @@ -81,25 +112,9 @@ export async function copyDirs( } try { if (file.endsWith(".art")) {// 模板文件 - const targetFile = path.join( - path.dirname(fileInfo.target), - path.basename(fileInfo.target, ".art") - ); - const shouldOverwrite = typeof opts.overwrite === 'function' - ? await Promise.resolve(opts.overwrite(targetFile)) - : opts.overwrite; - if (shouldOverwrite === false && existsSync(targetFile)) { - continue; - } - const template = artTemplate(fileInfo.source); - const templateVars =await getDynamicValue.call(opts,opts.vars,[file]); - await writeFile(targetFile, template(templateVars), {encoding:"utf-8"}); + await copyTemplateFile(fileInfo, opts); }else{// 普通文件 - const shouldOverwrite = await getDynamicValue.call(opts,opts.overwrite,[file]) as boolean - if (shouldOverwrite === false && existsSync(fileInfo.target)) { - continue; - } - await copyFile(fileInfo.source, fileInfo.target); + await copyRegularFile(fileInfo, opts); } if (typeof options?.after == "function") { if(options.after(fileInfo)===ABORT){ diff --git a/src/fs/copyFiles.ts b/src/fs/copyFiles.ts index b971ae3..c6cd865 100644 --- a/src/fs/copyFiles.ts +++ b/src/fs/copyFiles.ts @@ -31,15 +31,15 @@ export interface CopyFileInfo{ } export interface CopyFilesOptions { - vars? : Record | ((file: string) => Record | Promise>); // 传递给模板的变量 - ignore? : string[]; // 忽略的文件或文件夹,支持通配符 - clean? : boolean; // 是否清空目标文件夹 - cwd? : string; // pattern的cwd - overwrite?: boolean | ((filename: string) => boolean | Promise); // 是否覆盖已存在的文件,可以是boolean或返回boolean的同步/异步函数 - before? : (info:CopyFileInfo) => void | typeof ABORT; // 复制前的回调 - after? : (info:CopyFileInfo) => void | typeof ABORT; // 复制后的回调 - error? : (error:Error,{source,target}:{source: string, target: string})=>void | typeof ABORT // 复制出错的回调 - template?: Record | ((file: string) => Record | Promise>); + vars? : Record | ((file: string) => Record | Promise>); // 传递给模板的变量 + ignore? : string[]; // 忽略的文件或文件夹,支持通配符 + clean? : boolean; // 是否清空目标文件夹 + cwd? : string; // pattern的cwd + overwrite? : boolean | ((filename: string) => boolean | Promise); // 是否覆盖已存在的文件,可以是boolean或返回boolean的同步/异步函数 + before? : (info:CopyFileInfo) => void | typeof ABORT; // 复制前的回调 + after? : (info:CopyFileInfo) => void | typeof ABORT; // 复制后的回调 + error? : (error:Error,{source,target}:{source: string, target: string})=>void | typeof ABORT // 复制出错的回调 + templateOptions?: Record | ((file: string) => Record | Promise>); } export async function copyFiles( @@ -52,7 +52,7 @@ export async function copyFiles( clean : false }, options); - const { ignore, vars={}, cwd=process.cwd() } = opts; + const { ignore, cwd=process.cwd() } = opts; const srcDir = path.isAbsolute(pattern) ? path.dirname(pattern) : cwd; @@ -93,26 +93,10 @@ export async function copyFiles( } } try { - if (file.endsWith(".art")) {// 模板文件 - const targetFile = path.join( - path.dirname(fileInfo.target), - path.basename(fileInfo.target, ".art") - ); - const shouldOverwrite = typeof opts.overwrite === 'function' - ? await Promise.resolve(opts.overwrite(targetFile)) - : opts.overwrite; - if (shouldOverwrite === false && existsSync(targetFile)) { - continue; - } - const template = artTemplate(fileInfo.source); - const templateVars = await getDynamicValue.call(opts,opts.vars,[file]); - await writeFile(targetFile, template(templateVars), {encoding:"utf-8"}); - }else{// 模板文件 - const shouldOverwrite = await getDynamicValue.call(opts,opts.overwrite,[file]) as boolean - if (shouldOverwrite === false && existsSync(fileInfo.target)) { - continue; - } - await copyFile(fileInfo.source, fileInfo.target); + if (file.endsWith(".art")) { + await copyTemplateFile(fileInfo, opts); + } else { + await copyRegularFile(fileInfo, opts); } if (typeof options?.after == "function") { if(options.after(fileInfo)===ABORT){ @@ -132,6 +116,38 @@ export async function copyFiles( }); } +async function copyTemplateFile( fileInfo: Required,opts: CopyFilesOptions) { + const targetFile = path.join( + path.dirname(fileInfo.target), + path.basename(fileInfo.target, ".art") + ); + const shouldOverwrite = typeof opts.overwrite === 'function' + ? await Promise.resolve(opts.overwrite(targetFile)) + : opts.overwrite; + if (shouldOverwrite === false && existsSync(targetFile)) { + return; + } + const template = artTemplate(fileInfo.source); + template.defaults.imports.json=(v:any)=>{ + try{ + return JSON.stringify(v,null,4) + }catch{ + return v + } + } + const templateVars = await getDynamicValue.call(opts,opts.vars,[fileInfo.file]); + const templateOptions = await getDynamicValue.call(opts,opts.templateOptions,[fileInfo.file]); + await writeFile(targetFile, template(templateVars,templateOptions), { encoding:"utf-8" }); +} + +async function copyRegularFile( fileInfo: Required, opts: CopyFilesOptions) { + const shouldOverwrite = await getDynamicValue.call(opts,opts.overwrite,[fileInfo.file]) as boolean + if (shouldOverwrite === false && existsSync(fileInfo.target)) { + return; + } + await copyFile(fileInfo.source, fileInfo.target); +} + export { ABORT } from "../consts";