forked from nrwl/nx
/
generate-files.ts
127 lines (119 loc) · 3.38 KB
/
generate-files.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { readFileSync, readdirSync, statSync } from 'fs';
import * as path from 'path';
import type { Tree } from '@nrwl/tao/src/shared/tree';
import { logger } from '@nrwl/tao/src/shared/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');
allFilesInDir(srcFolder).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;
}