@tangelo/tangelo-configuration-toolkit
Version:
Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.
83 lines (68 loc) • 3 kB
JavaScript
const fs = require('fs-extra');
const globby = require('globby');
const minimatch = require('minimatch');
const path = require('path');
const rif = require('replace-in-file');
class PathSearcher {
#filter;
#ignorePaths = [_paths.tdi + '/**', 'config/cmscustom/tdi/**', '**/node_modules/**', '**/fonto/packages_shared/**', '**/fonto/platform/**'];
constructor (filter, ignoreProjectPaths) {
this.#filter = filter;
this.#ignorePaths.push(...ignoreProjectPaths);
}
#doFilter (paths) {
return this.#filter ? paths.filter(p => minimatch(p, this.#filter)) : paths;
}
get(globPath) {
return this.#doFilter(globby.sync(globPath, {dot: true, ignore: this.#ignorePaths}));
}
}
module.exports = function steps (step, dry, passedFilter, projectsWithType) {
if (Array.isArray(step)) {
step.forEach(substep => steps(substep, dry, passedFilter, projectsWithType));
return;
}
const {projectType = 'all', applyFilter = true, deletePaths, renamePaths, replaceInFiles, customAction} = step;
const projectsToIgnore = projectType === 'all' ? [] : projectsWithType.filter(p => p.tcl !== (projectType === 'tcl'));
const pathSearcher = new PathSearcher(applyFilter && passedFilter, projectsToIgnore.map(p => p.path + '/**'));
if (deletePaths) {
deletePaths.forEach(curpath => {
_info(`Deleting paths: ${curpath}`);
const paths = pathSearcher.get(curpath);
if (!dry) paths.forEach(p => fs.removeSync(p));
_write('Paths deleted:', paths.length);
});
}
if (renamePaths) {
renamePaths.forEach(([curpath, change]) => {
_info(`Renaming paths: ${curpath}`);
const paths = pathSearcher.get(curpath);
if (!dry) paths.forEach(p => fs.moveSync(p, path.join(p, change), {overwrite: true}));
_write('Paths renamed:', paths.length);
});
}
if (replaceInFiles) {
replaceInFiles.forEach(r => {
_info(`Executing replacements in files: ${r.files}`);
r.files = r.files.map(curpath => pathSearcher.get(curpath)).flat();
r.dry = dry;
if (r.fromtoPairs) {
r.from = r.fromtoPairs.map(p => p[0]);
r.to = r.fromtoPairs.map(p => p[1]);
}
let filesModCount;
for (let i=15/* safety limit*/; i>0 && r.files[0]; i--) { // execute repeatedly for modified files only
r.files = rif.sync(r).filter(f => f.hasChanged).map(f => f.file);
filesModCount ??= r.files.length; // save count only after first run (after this only subsets are processed)
if (i===1 && r.files[0]) _warn(`Repeated replacement stopped by safety limit - check file changes for too many content occurrences`);
if (dry) break;
}
_write('Files modified:', filesModCount);
});
}
if (!dry && customAction) {
customAction.forEach(([dirpath, actionFn]) => {
pathSearcher.get(dirpath).forEach(p => actionFn(p));
});
}
};