1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.generate = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const hooks_js_1 = require("./hooks.js");
|
6 | const codegen_js_1 = require("./codegen.js");
|
7 | const watcher_js_1 = require("./utils/watcher.js");
|
8 | const file_system_js_1 = require("./utils/file-system.js");
|
9 | const mkdirp_1 = tslib_1.__importDefault(require("mkdirp"));
|
10 | const path_1 = require("path");
|
11 | const debugging_js_1 = require("./utils/debugging.js");
|
12 | const config_js_1 = require("./config.js");
|
13 | const crypto_1 = require("crypto");
|
14 | const hash = (content) => (0, crypto_1.createHash)('sha1').update(content).digest('base64');
|
15 | async function generate(input, saveToFile = true) {
|
16 | const context = (0, config_js_1.ensureContext)(input);
|
17 | const config = context.getConfig();
|
18 | await context.profiler.run(() => (0, hooks_js_1.lifecycleHooks)(config.hooks).afterStart(), 'Lifecycle: afterStart');
|
19 | let previouslyGeneratedFilenames = [];
|
20 | function removeStaleFiles(config, generationResult) {
|
21 | const filenames = generationResult.map(o => o.filename);
|
22 |
|
23 | const staleFilenames = previouslyGeneratedFilenames.filter(f => !filenames.includes(f));
|
24 | staleFilenames.forEach(filename => {
|
25 | if (shouldOverwrite(config, filename)) {
|
26 | return (0, file_system_js_1.unlinkFile)(filename, err => {
|
27 | const prettyFilename = filename.replace(`${input.cwd || process.cwd()}/`, '');
|
28 | if (err) {
|
29 | (0, debugging_js_1.debugLog)(`Cannot remove stale file: ${prettyFilename}\n${err}`);
|
30 | }
|
31 | else {
|
32 | (0, debugging_js_1.debugLog)(`Removed stale file: ${prettyFilename}`);
|
33 | }
|
34 | });
|
35 | }
|
36 | });
|
37 | previouslyGeneratedFilenames = filenames;
|
38 | }
|
39 | const recentOutputHash = new Map();
|
40 | async function writeOutput(generationResult) {
|
41 | if (!saveToFile) {
|
42 | return generationResult;
|
43 | }
|
44 | if (config.watch) {
|
45 | removeStaleFiles(config, generationResult);
|
46 | }
|
47 | await context.profiler.run(async () => {
|
48 | await (0, hooks_js_1.lifecycleHooks)(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
|
49 | }, 'Lifecycle: beforeAllFileWrite');
|
50 | await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
|
51 | const exists = await (0, file_system_js_1.fileExists)(result.filename);
|
52 | if (!shouldOverwrite(config, result.filename) && exists) {
|
53 | return;
|
54 | }
|
55 | const content = result.content || '';
|
56 | const currentHash = hash(content);
|
57 | let previousHash = recentOutputHash.get(result.filename);
|
58 | if (!previousHash && exists) {
|
59 | previousHash = hash(await (0, file_system_js_1.readFile)(result.filename));
|
60 | }
|
61 | if (previousHash && currentHash === previousHash) {
|
62 | (0, debugging_js_1.debugLog)(`Skipping file (${result.filename}) writing due to indentical hash...`);
|
63 | return;
|
64 | }
|
65 | else if (context.checkMode) {
|
66 | context.checkModeStaleFiles.push(result.filename);
|
67 | return;
|
68 | }
|
69 | if (content.length === 0) {
|
70 | return;
|
71 | }
|
72 | recentOutputHash.set(result.filename, currentHash);
|
73 | const basedir = (0, path_1.dirname)(result.filename);
|
74 | await (0, hooks_js_1.lifecycleHooks)(result.hooks).beforeOneFileWrite(result.filename);
|
75 | await (0, hooks_js_1.lifecycleHooks)(config.hooks).beforeOneFileWrite(result.filename);
|
76 | await (0, mkdirp_1.default)(basedir);
|
77 | const absolutePath = (0, path_1.isAbsolute)(result.filename)
|
78 | ? result.filename
|
79 | : (0, path_1.join)(input.cwd || process.cwd(), result.filename);
|
80 | await (0, file_system_js_1.writeFile)(absolutePath, result.content);
|
81 | await (0, hooks_js_1.lifecycleHooks)(result.hooks).afterOneFileWrite(result.filename);
|
82 | await (0, hooks_js_1.lifecycleHooks)(config.hooks).afterOneFileWrite(result.filename);
|
83 | })), 'Write files');
|
84 | await context.profiler.run(() => (0, hooks_js_1.lifecycleHooks)(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
|
85 | return generationResult;
|
86 | }
|
87 |
|
88 | if (config.watch) {
|
89 | return (0, watcher_js_1.createWatcher)(context, writeOutput);
|
90 | }
|
91 | const outputFiles = await context.profiler.run(() => (0, codegen_js_1.executeCodegen)(context), 'executeCodegen');
|
92 | await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
|
93 | await context.profiler.run(() => (0, hooks_js_1.lifecycleHooks)(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
|
94 | if (context.profilerOutput) {
|
95 | await (0, file_system_js_1.writeFile)((0, path_1.join)(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
|
96 | }
|
97 | return outputFiles;
|
98 | }
|
99 | exports.generate = generate;
|
100 | function shouldOverwrite(config, outputPath) {
|
101 | const globalValue = config.overwrite === undefined ? true : !!config.overwrite;
|
102 | const outputConfig = config.generates[outputPath];
|
103 | if (!outputConfig) {
|
104 | (0, debugging_js_1.debugLog)(`Couldn't find a config of ${outputPath}`);
|
105 | return globalValue;
|
106 | }
|
107 | if (isConfiguredOutput(outputConfig) && typeof outputConfig.overwrite === 'boolean') {
|
108 | return outputConfig.overwrite;
|
109 | }
|
110 | return globalValue;
|
111 | }
|
112 | function isConfiguredOutput(output) {
|
113 | return typeof output.plugins !== 'undefined';
|
114 | }
|