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