* fix(core): automatically add root to the project.json projects * chore(core): move project-configuration generator utils to nx package * fix(core): add migrations to remove root
136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
import { readFileSync, readdirSync, statSync } from 'fs';
|
|
import * as path from 'path';
|
|
import type { Tree } from 'nx/src/generators/tree';
|
|
import { logger } from 'nx/src/utils/logger';
|
|
|
|
const binaryExts = new Set([
|
|
// // Image types originally from https://github.com/sindresorhus/image-type/blob/5541b6a/index.js
|
|
'.jpg',
|
|
'.jpeg',
|
|
'.png',
|
|
'.gif',
|
|
'.webp',
|
|
'.flif',
|
|
'.cr2',
|
|
'.tif',
|
|
'.bmp',
|
|
'.jxr',
|
|
'.psd',
|
|
'.ico',
|
|
'.bpg',
|
|
'.jp2',
|
|
'.jpm',
|
|
'.jpx',
|
|
'.heic',
|
|
'.cur',
|
|
'.tgz',
|
|
|
|
// Java files
|
|
'.jar',
|
|
'.keystore',
|
|
|
|
// Font files
|
|
'.ttf',
|
|
'.otf',
|
|
'.woff',
|
|
'.woff2',
|
|
'.eot',
|
|
]);
|
|
|
|
/**
|
|
* Generates a folder of files based on provided templates.
|
|
*
|
|
* While doing so it performs two substitutions:
|
|
* - Substitutes segments of file names surrounded by __
|
|
* - Uses ejs to substitute values in templates
|
|
*
|
|
* Examples:
|
|
* ```typescript
|
|
* generateFiles(tree, path.join(__dirname , 'files'), './tools/scripts', {tmpl: '', name: 'myscript'})
|
|
* ```
|
|
* This command will take all the files from the `files` directory next to the place where the command is invoked from.
|
|
* It will replace all `__tmpl__` with '' and all `__name__` with 'myscript' in the file names, and will replace all
|
|
* `<%= name %>` with `myscript` in the files themselves.
|
|
* `tmpl: ''` is a common pattern. With it you can name files like this: `index.ts__tmpl__`, so your editor
|
|
* doesn't get confused about incorrect TypeScript files.
|
|
*
|
|
* @param tree - the file system tree
|
|
* @param srcFolder - the source folder of files (absolute path)
|
|
* @param target - the target folder (relative to the tree root)
|
|
* @param substitutions - an object of key-value pairs
|
|
*/
|
|
export function generateFiles(
|
|
tree: Tree,
|
|
srcFolder: string,
|
|
target: string,
|
|
substitutions: { [k: string]: any }
|
|
): void {
|
|
const ejs = require('ejs');
|
|
|
|
const files = allFilesInDir(srcFolder);
|
|
if (files.length === 0) {
|
|
throw new Error(
|
|
`generateFiles: No files found in "${srcFolder}". Are you sure you specified the correct path?`
|
|
);
|
|
} else {
|
|
files.forEach((filePath) => {
|
|
let newContent: Buffer | string;
|
|
const computedPath = computePath(
|
|
srcFolder,
|
|
target,
|
|
filePath,
|
|
substitutions
|
|
);
|
|
|
|
if (binaryExts.has(path.extname(filePath))) {
|
|
newContent = readFileSync(filePath);
|
|
} else {
|
|
const template = readFileSync(filePath, 'utf-8');
|
|
try {
|
|
newContent = ejs.render(template, substitutions, {});
|
|
} catch (e) {
|
|
logger.error(`Error in ${filePath.replace(`${tree.root}/`, '')}:`);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
tree.write(computedPath, newContent);
|
|
});
|
|
}
|
|
}
|
|
|
|
function computePath(
|
|
srcFolder: string,
|
|
target: string,
|
|
filePath: string,
|
|
substitutions: { [k: string]: any }
|
|
): string {
|
|
const relativeFromSrcFolder = path.relative(srcFolder, filePath);
|
|
let computedPath = path.join(target, relativeFromSrcFolder);
|
|
if (computedPath.endsWith('.template')) {
|
|
computedPath = computedPath.substring(0, computedPath.length - 9);
|
|
}
|
|
Object.entries(substitutions).forEach(([propertyName, value]) => {
|
|
computedPath = computedPath.split(`__${propertyName}__`).join(value);
|
|
});
|
|
return computedPath;
|
|
}
|
|
|
|
function allFilesInDir(parent: string): string[] {
|
|
let res: string[] = [];
|
|
try {
|
|
readdirSync(parent).forEach((c) => {
|
|
const child = path.join(parent, c);
|
|
try {
|
|
const s = statSync(child);
|
|
if (!s.isDirectory()) {
|
|
res.push(child);
|
|
} else if (s.isDirectory()) {
|
|
res = [...res, ...allFilesInDir(child)];
|
|
}
|
|
} catch {}
|
|
});
|
|
} catch {}
|
|
return res;
|
|
}
|