我的 yeoman 生成器将文件从模板复制到目标路径:
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
在项目生成过程中,我需要将
this.props.appName
的值分配给某些文件名。
不幸的是,我不能像在这个文件中那样做:
<%=appName%>-project.sln
所有需要重命名的文件名称中都有
appTemplate
,所以我需要做的就是将appTemplate
替换为this.props.appName
的值。
我可以以某种方式配置
copyTpl
来重命名某些文件,同时将它们复制到另一个目的地吗?
好的,我找到了解决方案。根据 yeoman 文档:
任何生成器作者都可以注册一个transformStream来修改文件路径和/或内容。
使用此方法:
this.registerTransformStream();
这意味着我可以通过某个脚本传输所有生成的文件:
var rename = require("gulp-rename");
//other dependecies...
module.exports = yeoman.Base.extend({
//some other things generator do...
writing: function() {
var THAT = this;
this.registerTransformStream(rename(function(path) {
path.basename = path.basename.replace(/(666replacethat666)/g, THAT.props.appName);
path.dirname = path.dirname.replace(/(666replacethat666)/g, THAT.props.appName);
}));
this.fs.copyTpl(
this.templatePath(),
this.destinationPath(), {
appName: this.props.appName
});
}
});
此脚本将通过 gulp-rename 传输所有文件,将
666replacethat666
更改为更智能的内容。
如果您因为在 Yeoman 中使用
registerTransformStream
功能(断开转换流注册)而无法使用 composeWith()
,则可以使用 processDestinationPath
,它在您选择多个文件时起作用(而不是在您指定特定文件时起作用)在第一个参数中,出于某种原因)。
this.fs.copyTpl(
this.templatePath("**/{.*,*}"),
this.destinationPath(),
{ /* usually your prompt answers are here */ },
{},
{
processDestinationPath: (filePath: string) =>
filePath.replace(/somedir\/a-file.js/g, 'newdir/better-filename.js'),
},
);
文档选项来源:https://yeoman.github.io/generator/actions_fs.html#.copyTemplate
这是基于 https://github.com/SBoudrias/mem-fs-editor#copyfrom-to-options-context-templateoptions-
registerTransformStream
与 gulp-rename
仍然是一个问题。不过,我可以让它与 glob 一起使用。
const glob = require('glob');
writing() {
const files = glob.sync('**', { dot: true, nodir: true, cwd: this.templatePath() })
for (let i in files) {
this.fs.copyTpl(
this.templatePath(files[i]),
this.destinationPath( this.props.destinationFolderPath + '\\' + files[i].replace(/__fileName__/g,this.props.fileName)),
this.props
)
}
}
复制后,迭代输出目录的路径,并用正则表达式替换所有出现的位置。
const getReplacement = (base, pathRel, match, replace) => {
let pathRelNew = pathRel.replace(match, replace);
let oldPathAbs = path.join(base, pathRel);
let newPathAbs = path.join(base, pathRelNew);
if (oldPathAbs != newPathAbs) {
return {
oldPath: oldPathAbs,
newPath: newPathAbs
}
}
}
const getReplacementsRecursive = (base, match, replace, replacements = []) => {
let pathsRel = fs.readdirSync(base);
pathsRel.forEach(pathRel => {
if (fs.statSync(path.join(base, pathRel)).isDirectory()) {
replacements = getReplacementsRecursive(path.join(base, pathRel), match, replace, replacements);
var replacement = getReplacement(base, pathRel, match, replace)
if (replacement) replacements.push(replacement);
} else {
var replacement = getReplacement(base, pathRel, match, replace)
if (replacement) replacements.push(replacement);
}
});
return replacements;
};
function replaceMatches(dir, match, replace) {
var replacements = getReplacementsRecursive(dir, match, replace);
replacements.forEach(function(replacement) {
fs.renameSync(replacement.oldPath, replacement.newPath);
});
}
module.exports = class extends Generator {
// ...
writing() {
// don't forget to set the output directory
let OUTPUT_DIR = "./out";
// this.fs.copyTpl(...);
// setTimeout is used to give some time for the copyTpl to finish
setTimeout(
() => {
var match = new RegExp( "666replacethat666", 'g' );
replaceMatches(OUTPUT_DIR, match, this.props.appName);
}, 1000);
}
}
我建议在模板操作后简单地重命名目标文件。
我从这个讨论中得到了这个解决方案:在 Yeoman 复制模板文件后重命名文件
示例:
// start by doing the large template operation with a glob
this.fs.copyTpl(
this.templatePath("**/*"),
this.destinationPath(),
this.answers,
);
// Example of a directory rename - moving the ApplicationName directory and everything in it
this.fs.move(
this.destinationPath('src', 'ApplicationName', '**/*'),
this.destinationPath('src', this.answers.appName, '**/*')
);
// Renaming a single file. Note how we are now operating within the renamed directory
this.fs.move(
this.destinationPath('src', this.answers.appName, 'ApplicationName.csproj'),
this.destinationPath('src', this.answers.appName, this.answers.appName + '.csproj')
);