UNPKG

19.4 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22exports.specialPathResolve = exports.loadBlock = exports.loadBlocks = exports.loadDockerBlocks = exports.buildBlock = exports.watchBlock = exports.buildBlocksOrBundles = exports.cleanNodeFiles = exports.updateVersions = void 0;
23const backlib_1 = require("backlib");
24const chokidar = __importStar(require("chokidar"));
25const fs = __importStar(require("fs-extra"));
26const p_spawn_1 = require("p-spawn");
27const Path = __importStar(require("path"));
28const processors_1 = require("./processors");
29const utils_1 = require("./utils");
30const vdev_config_1 = require("./vdev-config");
31// --------- /Public Types --------- //
32async function updateVersions(config) {
33 var _a, _b;
34 if (!config) {
35 config = await vdev_config_1.loadVdevConfig();
36 }
37 const versionFiles = (_b = (_a = config.version) === null || _a === void 0 ? void 0 : _a.files) !== null && _b !== void 0 ? _b : null;
38 // if we do not have version files, we skip.
39 if (versionFiles == null) {
40 return;
41 }
42 const newVersion = config.__version__;
43 let firstUpdate = false; // flag that will be set
44 try {
45 for (let file of versionFiles) {
46 const originalContent = (await fs.readFile(file, 'utf8')).toString();
47 const isHTML = file.toLowerCase().endsWith('html');
48 let fileAppVersion = getVersion(originalContent, isHTML);
49 if (newVersion !== fileAppVersion) {
50 // On the first update needed, we start the log section for the version update
51 if (!firstUpdate) {
52 console.log(`----- Version Update: Updating '__version__ = ".."' or '?v=..' to ${newVersion} `);
53 firstUpdate = true;
54 }
55 console.log(`Changing ${fileAppVersion} -> ${newVersion} in file: ${file}`);
56 let newContent = replaceVersion(originalContent, newVersion, isHTML);
57 await fs.writeFile(file, newContent, 'utf8');
58 }
59 else {
60 // Note: for now, we do not log when nothing to do.
61 }
62 }
63 }
64 catch (ex) {
65 throw new Error(`ERROR while doing versioning files - ${ex.message}`);
66 }
67 // if we have at least one update, we close the log section.
68 if (firstUpdate) {
69 console.log('----- /Version Update: done');
70 }
71}
72exports.updateVersions = updateVersions;
73// FIXME: Needs to look at the "blocks" from the config
74async function cleanNodeFiles() {
75 const filesToDelete = ['./package-lock.json', './node_blockules'];
76 const blocks = await loadBlocks();
77 // dirs.unshift('./'); // we do not clean the base dir, as it is easy to do by hand, and then, scripts won't work
78 // TODO: probably need to add web-server as well
79 for (const block of Object.values(blocks)) {
80 const dir = block.dir;
81 for (let fName of filesToDelete) {
82 const fileToDelete = Path.join(dir, fName);
83 if ((await fs.pathExists(fileToDelete))) {
84 await backlib_1.saferRemove(fileToDelete);
85 }
86 }
87 }
88}
89exports.cleanNodeFiles = cleanNodeFiles;
90/**
91 *
92 * @param names List of block name or block/bundle names
93 */
94async function buildBlocksOrBundles(names) {
95 if (names.length === 0) {
96 const blocks = await loadBlocks();
97 for (let block of Object.values(blocks)) {
98 await _buildBlock(block);
99 }
100 }
101 else {
102 for (let name of names) {
103 const blockAndBundle = name.split('/');
104 // if only .length === 1 then blockAndBundle[1] which is fine
105 await buildBlock(blockAndBundle[0], { onlyBundleName: blockAndBundle[1] });
106 }
107 }
108}
109exports.buildBlocksOrBundles = buildBlocksOrBundles;
110// TODO: needs to add support for any block rule watch
111// TODO: needs to add support for only one bundle watch
112async function watchBlock(blockName) {
113 var _a;
114 const blocks = await loadBlocks();
115 const block = blocks[blockName];
116 const webBundles = (block) ? block.webBundles : null;
117 if (webBundles == null) {
118 throw new Error(`Block ${blockName} not found or does not have a '.webBundles'. As of now, can only watch webBundles`);
119 }
120 for (let bundle of webBundles) {
121 await initWebBundle(block, bundle);
122 // The rollup have a watch block, so we use it
123 if (bundle.type === 'js' || bundle.type === 'ts') {
124 if (bundle.watch) {
125 console.log(`WARNING - Ignoring '.watch' property for bundle ${bundle.name} for .js/.ts processing
126 as rollup watches dependencies. (advice: remove this .watch property for clarity)`);
127 }
128 await _buildBlock(block, bundle, { watch: true });
129 }
130 // Otherwise, we just watch the entries or the watch, and rebuild everything
131 else {
132 await _buildBlock(block, bundle);
133 const toWatch = (_a = bundle.watch) !== null && _a !== void 0 ? _a : bundle.entries;
134 let watcher = chokidar.watch(toWatch, { persistent: true });
135 // TODO: Needs to use a call reducer
136 watcher.on('change', async function (filePath, stats) {
137 if (filePath.endsWith(`.${bundle.type}`)) {
138 await _buildBlock(block, bundle);
139 }
140 });
141 }
142 }
143}
144exports.watchBlock = watchBlock;
145const blockBuilt = new Set();
146/**
147 * Build a and block and eventually a bundle
148 * @param blockName
149 * @param opts
150 */
151async function buildBlock(blockName, opts) {
152 const blockByName = await loadBlocks();
153 const block = blockByName[blockName];
154 if (blockBuilt.has(block.name)) {
155 console.log(`------ Block ${block.name} already built - SKIP\n`);
156 return;
157 }
158 if (!block) {
159 throw new Error(`No block found for blockeName ${blockName}.`);
160 }
161 let bundle;
162 const onlyBundleName = opts === null || opts === void 0 ? void 0 : opts.onlyBundleName;
163 if (onlyBundleName && block.webBundles) {
164 bundle = block.webBundles.find((b) => (b.name == onlyBundleName));
165 if (!bundle) {
166 throw new Error(`No webBundle ${onlyBundleName} found in block ${block.name}`);
167 }
168 await initWebBundle(block, bundle);
169 }
170 await _buildBlock(block, bundle, opts);
171 blockBuilt.add(block.name);
172}
173exports.buildBlock = buildBlock;
174async function _buildBlock(block, bundle, opts) {
175 const hasPomXml = await fs.pathExists(Path.join(block.dir, 'pom.xml'));
176 const hasPackageJson = await fs.pathExists(Path.join(block.dir, 'package.json'));
177 const hasTsConfig = await fs.pathExists(Path.join(block.dir, 'tsconfig.json'));
178 const hasWebBundles = (block.webBundles) ? true : false;
179 // Note: if we have a bundleName, then, just the bundle log will be enough.
180 const start = utils_1.now();
181 if (!bundle) {
182 console.log(`------ Building Block ${block.name} ${block.dir}`);
183 }
184 // no matter what, if we have a pckageJson, we make sure we do a npm install
185 if (hasPackageJson) {
186 await npmInstall(block);
187 }
188 // if we have a webBundles, we build it
189 if (hasWebBundles) {
190 // TODO: need to allow to give a bundle name to just build it
191 await buildWebBundles(block, bundle, opts);
192 }
193 // run tsc (with clean dist/ folder), if it is not a webBundle (assume rollup will take care of the ts when webBundles)
194 if (!hasWebBundles && hasTsConfig) {
195 await buildTsSrc(block);
196 }
197 if (hasPomXml) {
198 await runMvn(block, opts ? opts.full : false);
199 }
200 if (!bundle) {
201 await utils_1.printLog(`------ Building Block ${block.name} DONE`, start);
202 console.log();
203 }
204}
205async function npmInstall(block) {
206 await p_spawn_1.spawn('npm', ['install'], { cwd: block.dir });
207}
208async function buildTsSrc(block) {
209 const distDirNeedsDelete = false;
210 const distDir = Path.join(block.dir, '/dist/');
211 const distDirExist = await fs.pathExists(distDir);
212 // if we have distDirExist, check that it define as compileOptions.outDir in
213 if (distDirExist) {
214 const tsconfigObj = await utils_1.readJsonFileWithComments(Path.join(block.dir, 'tsconfig.json'));
215 let outDir = tsconfigObj.compilerOptions.outDir;
216 outDir = (outDir) ? Path.join(block.dir, outDir, '/') : null; // add a ending '/' to normalize all of the dir path with ending / (join will remove duplicate)
217 if (outDir === distDir) {
218 console.log(`tsc prep - deleting tsc distDir ${distDir}`);
219 await backlib_1.saferRemove(distDir);
220 }
221 else {
222 console.log(`tss prep - skipping tsc distDir ${distDir} because does not match tsconfig.json compilerOptions.outDir ${outDir}`);
223 }
224 }
225 // Assume there is a typescript installed in the root project
226 await p_spawn_1.spawn('./node_modules/.bin/tsc', ['-p', block.dir]);
227}
228async function runMvn(block, full) {
229 const args = ['clean', 'package'];
230 if (!full) {
231 args.push('-Dmaven.test.skip=true');
232 }
233 var start = utils_1.now();
234 await p_spawn_1.spawn('mvn', args, {
235 toConsole: false,
236 cwd: block.dir,
237 onStderr: function (data) {
238 process.stdout.write(data);
239 }
240 });
241 await utils_1.printLog(`maven build ${full ? 'with test' : ''}`, start);
242}
243// bundlers by type (which is file extension without '.')
244const bundlers = {
245 ts: buildTsBundler,
246 pcss: buildPcssBundler,
247 tmpl: buildTmplBundler,
248 html: buildTmplBundler,
249 js: buildJsBundler
250};
251async function buildWebBundles(block, onlyBundle, opts) {
252 let webBundles;
253 if (onlyBundle) {
254 // the onlyBundle is already initialized
255 webBundles = [onlyBundle];
256 }
257 else {
258 webBundles = block.webBundles;
259 // we need to initialize the webBundles
260 for (let bundle of webBundles) {
261 await initWebBundle(block, bundle);
262 }
263 }
264 for (let bundle of webBundles) {
265 await ensureDist(bundle);
266 var start = utils_1.now();
267 await bundlers[bundle.type](block, bundle, opts);
268 if (opts === null || opts === void 0 ? void 0 : opts.watch) {
269 await utils_1.printLog(`Starting watch mode for ${block.name}/${bundle.name} (${bundle.dist})`, start);
270 }
271 else {
272 await utils_1.printLog(`Building bundle ${block.name}/${bundle.name}`, start, bundle.dist);
273 }
274 }
275}
276const rollupOptionsDefaults = {
277 ts: {
278 watch: false,
279 ts: true,
280 tsconfig: './tsconfig.json'
281 },
282 js: {
283 watch: false,
284 ts: false
285 }
286};
287/**
288 * Initialize all of the bundle properties accordingly.
289 * This allow the bundlers and other logic to not have to worry about default values and path resolution.
290 */
291async function initWebBundle(block, bundle) {
292 bundle.type = Path.extname(utils_1.asNames(bundle.entries)[0]).substring(1);
293 // for now, just take the block.dir
294 bundle.dir = specialPathResolve('', block.dir, bundle.dir);
295 // Make the entries relative to the Block
296 bundle.entries = utils_1.asNames(bundle.entries).map((f) => specialPathResolve('', bundle.dir, f));
297 // If bundle.watch, same as entries above
298 if (bundle.watch) {
299 // Make the watch relative to the Block
300 bundle.watch = utils_1.asNames(bundle.watch).map((f) => specialPathResolve('', bundle.dir, f));
301 }
302 // resolve the dist
303 bundle.dist = specialPathResolve('', block.baseDistDir, bundle.dist);
304 // --------- rollupOptions initialization --------- //
305 if (bundle.type === 'ts' || bundle.type === 'js') {
306 // get the base default options for this type
307 const rollupOptionsDefault = rollupOptionsDefaults[bundle.type];
308 // override default it if bundle has one
309 const rollupOptions = (bundle.rollupOptions) ? { ...rollupOptionsDefault, ...bundle.rollupOptions }
310 : { ...rollupOptionsDefault };
311 // resolve tsconfig
312 if (rollupOptions.tsconfig) {
313 rollupOptions.tsconfig = specialPathResolve('', bundle.dir, rollupOptions.tsconfig);
314 }
315 // set the new optoins back.
316 bundle.rollupOptions = rollupOptions;
317 }
318 // --------- /rollupOptions initialization --------- //
319}
320// --------- /Private WebBundle Utils --------- //
321// --------- Private Bundlers --------- //
322async function buildTsBundler(block, bundle, opts) {
323 // TODO: need to re-enable watch
324 try {
325 if (opts && opts.watch) {
326 bundle.rollupOptions.watch = true;
327 }
328 // resolve all of the entries (with glob)
329 const allEntries = await resolveGlobs(bundle.entries);
330 await processors_1.rollupFiles(allEntries, bundle.dist, bundle.rollupOptions);
331 }
332 catch (ex) {
333 // TODO: need to move exception ahndle to the caller
334 console.log("BUILD ERROR - something when wrong on rollup\n\t", ex);
335 console.log("Empty string was save to the app bundle");
336 console.log("Trying saving again...");
337 return;
338 }
339}
340async function buildPcssBundler(block, bundle, opts) {
341 const allEntries = await resolveGlobs(bundle.entries);
342 await processors_1.pcssFiles(allEntries, bundle.dist);
343}
344async function buildTmplBundler(block, bundle, opts) {
345 const allEntries = await resolveGlobs(bundle.entries);
346 await processors_1.tmplFiles(allEntries, bundle.dist);
347}
348async function buildJsBundler(block, bundle, opts) {
349 if (opts && opts.watch) {
350 bundle.rollupOptions.watch = true;
351 }
352 const allEntries = await resolveGlobs(bundle.entries);
353 await processors_1.rollupFiles(allEntries, bundle.dist, bundle.rollupOptions);
354}
355// --------- /Private Bundlers --------- //
356// --------- Public Loaders --------- //
357async function loadDockerBlocks() {
358 const blocks = await loadBlocks();
359 const dockerBlocks = {};
360 for (let block of Object.values(blocks)) {
361 const hasDockerfile = await fs.pathExists(Path.join(block.dir, 'Dockerfile'));
362 if (hasDockerfile) {
363 dockerBlocks[block.name] = block;
364 }
365 }
366 return dockerBlocks;
367}
368exports.loadDockerBlocks = loadDockerBlocks;
369async function loadBlocks() {
370 const rawConfig = await vdev_config_1.loadVdevConfig();
371 const rawBlocks = rawConfig.blocks;
372 const base = {
373 system: rawConfig.system,
374 __version__: rawConfig.__version__,
375 imageTag: rawConfig.imageTag
376 };
377 // build the services map from the raw services list
378 const blockByName = rawBlocks.map((item) => {
379 let block;
380 let name;
381 // initialize the object
382 if (typeof item === 'string') {
383 block = {
384 name: item
385 };
386 }
387 else {
388 if (!item.name) {
389 throw new Error(`the build config file vdev.yaml has a block without '.name'`);
390 }
391 // we do a shallow clone
392 block = { ...item };
393 }
394 //// add the system/version (they should not been set in the block anyway)
395 if (block.system != null || block.__version__ != null) {
396 throw new Error(`.system or .__version__ cannot be set at the block level (but found in ${block.name})`);
397 }
398 Object.assign(block, base);
399 // if the block does not have a dir, then, build it with the parent one
400 if (!block.dir) {
401 block.dir = Path.join(rawConfig.baseBlockDir, `${block.name}/`);
402 }
403 return block;
404 }).reduce((map, block) => {
405 map[block.name] = block;
406 return map;
407 }, {});
408 return blockByName;
409}
410exports.loadBlocks = loadBlocks;
411async function loadBlock(name) {
412 const blocks = await loadBlocks();
413 const block = blocks[name];
414 if (!block) {
415 throw new Error(`Block ${name} not found`);
416 }
417 return block;
418}
419exports.loadBlock = loadBlock;
420// --------- /Public Loaders --------- //
421// --------- Private Utils --------- //
422/** Since 0.11.18 each string glob is sorted within their match, but if globs is an array, the order of each result glob result is preserved. */
423async function resolveGlobs(globs) {
424 if (typeof globs === 'string') {
425 return backlib_1.glob(globs);
426 }
427 else {
428 const lists = [];
429 for (const globStr of globs) {
430 const list = await backlib_1.glob(globStr);
431 lists.push(list);
432 }
433 return lists.flat();
434 }
435}
436//#region ---------- version Utils ----------
437/** Return the first version found. For html, looks for the `src|href=....?v=___` and for other files the version = ... */
438function getVersion(content, isHtml = false) {
439 // look for the href or src ?v=...
440 if (isHtml) {
441 const rgx = /<.*(href|src).*?v=(.*?)(\"|\&)/gm;
442 const r = rgx.exec(content);
443 if (r != null && r.length > 2) {
444 return r[2];
445 }
446 else {
447 return null;
448 }
449 }
450 // look for the version = ...
451 else {
452 var rx = new RegExp('__version__' + '\\s*[=:]\\s*[\'"](.*)[\'"]', 'i');
453 var match = content.match(rx);
454 return (match) ? match[1] : null;
455 }
456}
457function replaceVersion(content, value, isHtml = false) {
458 if (isHtml) {
459 const rgxRep = /(<.*(href|src).*?v=).*?(\"|\&.*)/g;
460 // $2 not is not used because it is included as part of $1
461 return content.replace(rgxRep, '$1' + value + '$3');
462 }
463 else {
464 var rx = new RegExp('(.*' + '__version__' + '\\s*[=:]\\s*["\']).*([\'"].*)', 'i');
465 content = content.replace(rx, '$1' + value + '$2');
466 return content;
467 }
468}
469//#endregion ---------- /version Utils ----------
470async function ensureDist(bundle) {
471 const distDir = Path.dirname(bundle.dist);
472 await fs.ensureDir(distDir);
473}
474/**
475 * Special resolve that
476 * - if finalPath null, then, return dir.
477 * - resolve any path to dir if it starts with './' or '../',
478 * - absolute path if it starts with '/'
479 * - baseDir if the path does not start with either '/' or './'
480 * @param baseDir
481 * @param dir
482 * @param finalPath dir or file path
483 */
484function specialPathResolve(baseDir, dir, finalPath) {
485 if (finalPath == null) {
486 return dir;
487 }
488 if (finalPath.startsWith('/')) {
489 return finalPath;
490 }
491 if (finalPath.startsWith('./') || finalPath.startsWith('../')) {
492 return Path.join(dir, finalPath);
493 }
494 return Path.join(baseDir, finalPath);
495}
496exports.specialPathResolve = specialPathResolve;
497// --------- /Private Utils --------- //