-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.js
More file actions
281 lines (254 loc) · 7.65 KB
/
build.js
File metadata and controls
281 lines (254 loc) · 7.65 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
const fs = require('fs');
const path = require('path');
const watch = require('watch');
const ProgressBar = require('progress');
const ngTemplate = require('angular-template-cache');
const ngAnnotate = require('ng-annotate');
const browserListRegexp = require('browserslist-useragent-regexp');
/* Arguments */
const args = process.argv.slice(2);
const doWatch = args.indexOf('--watch') !== -1;
const doVerbose = args.indexOf('--verbose') !== -1;
const log = doVerbose ? console.log : () => {};
/* Paths */
const pathRoot = '..';
const pathTmp = path.join(pathRoot, 'build/cli');
const pathSrc = path.join(pathRoot, 'src/main');
const fileStyles = path.join(pathTmp, 'src/main/_bundle.scss');
const fileTemplates = path.join(pathTmp, 'src/main/app/templates.js');
const fileBrowsers = path.join(pathTmp, 'src/main/browserRegexp.js');
/* Custom watch filter */
const watchFilter = function(path, stats) {
return _contains(pathSrc, path) && (!stats.isFile() || path.match(/^.+(?:\.js|\.scss|\.html)$/));
};
// create temp directory
ensureParent(pathTmp);
if (!fs.existsSync(pathTmp)) {
fs.mkdirSync(pathTmp);
}
// build files and start watching
watch.watchTree(pathRoot, {filter: watchFilter, interval: 1}, (result, curr, prev) => {
if (typeof result === "object" && prev === null && curr === null) {
// finished walking the tree
const files = Object.keys(result);
const scripts = files.filter(_isScript);
const templates = files.filter(_isTemplate);
const styles = files.filter(_isStyle).sort();
log('Processing files:');
log(('' + scripts.length).padStart(6) + ' scripts');
log(('' + templates.length).padStart(6) + ' templates');
log(('' + styles.length).padStart(6) + ' styles');
// annotate all scripts
const progressScripts = progress('Annotating scripts', scripts.length);
scripts.forEach(file => {
copy(file, data => ngAnnotate(data, {add: true}).src);
progressScripts.tick();
});
// generate style index
const progressStyles = progress('Generating styles', styles.length + 1);
styles.forEach(file => {
copy(file);
progressStyles.tick();
});
fs.writeFileSync(ensureParent(fileStyles), styles
.filter(s => _contains(path.join(pathSrc, 'app'), s))
.map(_toStyleImport)
.join('\n') + '\n', 'utf8');
progressStyles.tick();
// generating supported browsers list
const browserRegexp = browserListRegexp.getUserAgentRegExp({
allowHigherVersions: true
});
const progressBrowsers = progress('Generating supported browser list', 1);
fs.writeFileSync(fileBrowsers, `module.exports = ${browserRegexp}`);
progressBrowsers.tick();
// generate template cache
const progressTemplates = progress('Generating templates', 2);
progressTemplates.tick();
buildTemplateCache(() => {
progressTemplates.tick();
if (doWatch) {
log("Watching...");
} else {
process.exit();
}
});
} else if (prev === null) {
// file was created
if (_isScript(result)) {
log('Adding script: ' + result);
copy(result, data => ngAnnotate(data, {add: true}).src);
} else if (_isStyle(result)) {
log('Adding style: ' + result);
copy(result);
if (_contains(path.join(pathSrc, 'app'), result)) {
addLine(fileStyles, _toStyleImport(result) + '\n');
}
} else if (_isTemplate(result)) {
log('Adding template: ' + result);
buildTemplateCache();
}
} else if (curr.nlink === 0) {
// file was removed
if (_isScript(result)) {
log('Removing script: ' + result);
remove(result);
} else if (_isStyle(result)) {
log('Removing style: ' + result);
remove(result);
if (_contains(path.join(pathSrc, 'app'), result)) {
removeLine(fileStyles, _toStyleImport(result) + '\n');
}
} else if (_isTemplate(result)) {
log('Removing template: ' + result);
buildTemplateCache();
}
} else {
// file was changed
if (_isScript(result)) {
log('Updating script: ' + result);
copy(result, data => ngAnnotate(data, {add: true}).src);
} else if (_isStyle(result)) {
log('Updating style: ' + result);
copy(result);
} else if (_isTemplate(result)) {
log('Updating template: ' + result);
buildTemplateCache();
}
}
});
/**
* Copies the given file and optionally transforms it.
*
* @param file the file path
* @param transform a transformation function
*/
function copy(file, transform) {
const data = fs.readFileSync(file, 'utf8');
const res = transform ? transform(data) : data;
const tmp = ensureParent(path.join(pathTmp, 'rel', file));
fs.writeFileSync(tmp, res, 'utf8');
}
/**
* Builds the template cache using ngTemplate.
*
* @param callback a callback to be executed when the process finished
*/
function buildTemplateCache(callback) {
ngTemplate({
filesGlob: '../src/**/*.html',
fileList: [],
strict: true,
ignoreMissing: false,
style: 'browser',
header: '// auto-generated file automatically generated by angular-template-cache',
moduleName: 'commons.templates',
newModule: true,
basePath: '../src/main/',
quotmark: 'single',
whitespace: 'spaces',
htmlmin: true,
htmlminOptions: {
caseSensitive: true,
collapseWhitespace: true,
conservativeWhitespace: true,
includeAutoGeneratedTags: false
},
output: ensureParent(fileTemplates)
}).then(callback);
}
/**
* Appends the given line to the end of the file.
*
* @param file the file path
* @param line the line to be added
*/
function addLine(file, line) {
fs.appendFileSync(file, line, 'utf8');
}
/**
* Removes the given line from the file.
*
* @param file the file path
* @param line the line to be removed
*/
function removeLine(file, line) {
const data = fs.readFileSync(file, 'utf8');
fs.writeFileSync(file, data.replace(line), 'utf8');
}
/**
* Ensures the existence of the parent folder of the given file.
*
* @param file the file path
* @returns {string} the file path
*/
function ensureParent(file) {
const name = path.dirname(file);
if (!fs.existsSync(name)) {
ensureParent(name);
fs.mkdirSync(name);
}
return file;
}
/**
* Deletes the given file and recursively deletes the parent folder if it is empty.
*
* @param file the file path
*/
function remove(file) {
const tmp = path.join(pathTmp, file);
fs.unlink(tmp, err => {
if (err) throw err;
removeParentIfEmpty(tmp);
});
}
/**
* Recursively deletes the parent folder of the given file if it is empty.
*
* @param file the file path
*/
function removeParentIfEmpty(file) {
const name = path.dirname(file);
if (name !== pathTmp) {
fs.readdir(name, (err, files) => {
if (err) throw err;
if (files.length === 0) {
fs.rmdir(name, err => {
if (err) throw err;
removeParentIfEmpty(name);
});
}
});
}
}
/**
* Creates a new progress bar.
*
* @param title the title of the progress bar
* @param total the total number of steps of the progress bar
* @returns {ProgressBar} the progress bar
*/
function progress(title, total) {
return new ProgressBar(title + ': [:bar] :percent in :elapseds', {
width: 20,
complete: '=',
incomplete: ' ',
total: total,
stream: process.stdout
});
}
function _toStyleImport(file) {
return '@import "./' + path.relative(pathSrc, file).replace(/\\/g,"/") + '";'
}
function _isScript(file) {
return !file.includes('_scsslint_tmp') && file.endsWith('.js');
}
function _isStyle(file) {
return file.endsWith('.scss');
}
function _isTemplate(file) {
return file.endsWith('.html');
}
function _contains(p1, p2) {
return p1.startsWith(p2) || p2.startsWith(p1);
}