@hypernym/bundler 0.14.4 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,254 @@
1
+ import process, { cwd } from "node:process";
2
+ import { parse, resolve } from "node:path";
3
+ import { stat } from "node:fs/promises";
4
+ import { dim } from "@hypernym/colors";
5
+ import { isUndefined } from "@hypernym/utils";
6
+ import { copy, readdir, write } from "@hypernym/utils/fs";
7
+ import { rolldown } from "rolldown";
8
+ import { dts } from "rolldown-plugin-dts";
9
+ import { outputPaths } from "../plugins/index.mjs";
10
+
11
+ //#region src/bin/meta.ts
12
+ const name = `Hyperbundler`;
13
+
14
+ //#endregion
15
+ //#region src/utils/logger.ts
16
+ const cl = console.log;
17
+ const separator = `|`;
18
+ const logger = {
19
+ info: (...args) => {
20
+ cl(name, dim(separator), ...args);
21
+ },
22
+ error: (...args) => {
23
+ cl();
24
+ cl(name, dim(separator), ...args);
25
+ cl();
26
+ },
27
+ exit: (message) => {
28
+ cl();
29
+ cl(name, dim(separator), message);
30
+ cl();
31
+ return process.exit();
32
+ }
33
+ };
34
+
35
+ //#endregion
36
+ //#region src/utils/error.ts
37
+ function error(err) {
38
+ logger.error("Something went wrong...");
39
+ console.error(err);
40
+ return process.exit();
41
+ }
42
+
43
+ //#endregion
44
+ //#region src/utils/format-ms.ts
45
+ function formatMs(ms) {
46
+ const s = 1e3;
47
+ const m = s * 60;
48
+ const h = m * 60;
49
+ const msAbs = Math.abs(ms);
50
+ if (msAbs >= h) return `${(ms / h).toFixed(2)}h`;
51
+ if (msAbs >= m) return `${(ms / m).toFixed(2)}m`;
52
+ if (msAbs >= s) return `${(ms / s).toFixed(2)}s`;
53
+ return `${ms}ms`;
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/utils/format-bytes.ts
58
+ function formatBytes(bytes) {
59
+ const decimals = 2;
60
+ const units = [
61
+ "B",
62
+ "KB",
63
+ "MB",
64
+ "GB",
65
+ "TB"
66
+ ];
67
+ if (bytes === 0) return `0 B`;
68
+ const k = 1024;
69
+ const dm = decimals < 0 ? 0 : decimals;
70
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
71
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${units[i]}`;
72
+ }
73
+
74
+ //#endregion
75
+ //#region src/utils/get-output-path.ts
76
+ function getOutputPath(outDir, input, { extension = "auto" } = {}) {
77
+ const src = input.startsWith("./") ? input.slice(2) : input;
78
+ let output = src.includes("/") ? src.replace(src.split("/")[0], outDir) : `${outDir}/${src}`;
79
+ if (extension !== "original") {
80
+ const ext = output.match(/\.[^/.]+$/)?.[0] ?? "";
81
+ const esm = [
82
+ ".js",
83
+ ".mjs",
84
+ ".ts",
85
+ ".mts"
86
+ ];
87
+ const legacy = [".cjs", ".cts"];
88
+ let newExt = "";
89
+ if (esm.includes(ext)) newExt = extension === "dts" ? ".d.mts" : ".mjs";
90
+ else if (legacy.includes(ext)) newExt = extension === "dts" ? ".d.cts" : ".cjs";
91
+ if (newExt) output = `${output.slice(0, -ext.length)}${newExt}`;
92
+ }
93
+ return outDir.startsWith("./") || outDir.startsWith("../") ? output : `./${output}`;
94
+ }
95
+ function parseOutputPath(path) {
96
+ if (!path) return;
97
+ if (path.startsWith("./")) return path;
98
+ else return `./${path}`;
99
+ }
100
+
101
+ //#endregion
102
+ //#region src/bin/build.ts
103
+ function logEntryStats(stats) {
104
+ const cl$1 = console.log;
105
+ const base = parse(stats.path).base;
106
+ const path = stats.path.replace(base, "");
107
+ let format = stats.format;
108
+ if (format === "commonjs") format = "cjs";
109
+ if (format === "es" || format === "module") format = "esm";
110
+ const pathDim = dim(path);
111
+ const output = pathDim + base;
112
+ const outputLength = output.length + 2;
113
+ cl$1("▸", format.padEnd(5), output.padEnd(outputLength), dim(`[${formatBytes(stats.size)}, ${formatMs(stats.buildTime)}]`));
114
+ if (stats.logs) for (const log of stats.logs) cl$1("!", log.level.padEnd(5), output.padEnd(outputLength), dim(log.log.message));
115
+ }
116
+ async function build(options) {
117
+ const { cwd: cwdir = cwd(), outDir = "dist", entries, externals, tsconfig, hooks, minify } = options;
118
+ let start = 0;
119
+ const buildStats = {
120
+ cwd: cwdir,
121
+ size: 0,
122
+ buildTime: 0,
123
+ files: []
124
+ };
125
+ await hooks?.["build:start"]?.(options, buildStats);
126
+ if (entries) {
127
+ start = Date.now();
128
+ for (const entry of entries) {
129
+ const entryStart = Date.now();
130
+ if (entry.input || entry.dts) {
131
+ const buildLogs = [];
132
+ const isChunk = !isUndefined(entry.input);
133
+ const outputRawPath = parseOutputPath(entry.output) || getOutputPath(outDir, entry.input || entry.dts, { extension: isChunk ? "auto" : "dts" });
134
+ const outputResolvePath = resolve(cwdir, outputRawPath);
135
+ let format = entry.format || "esm";
136
+ if (outputRawPath.endsWith(".cjs")) format = "cjs";
137
+ const entryInput = {
138
+ input: resolve(cwdir, entry.input || entry.dts),
139
+ external: entry.externals || externals,
140
+ plugins: isChunk ? entry.plugins : entry.plugins || [dts({
141
+ ...entry.dtsPlugin,
142
+ emitDtsOnly: true
143
+ })],
144
+ onLog: (level, log, handler) => {
145
+ if (entry.onLog) entry.onLog(level, log, handler, buildLogs);
146
+ else buildLogs.push({
147
+ level,
148
+ log
149
+ });
150
+ },
151
+ resolve: entry.resolve,
152
+ define: entry.define,
153
+ inject: entry.inject,
154
+ tsconfig: entry.tsconfig || tsconfig
155
+ };
156
+ const entryOutput = {
157
+ file: isChunk ? outputResolvePath : void 0,
158
+ minify: isChunk ? !isUndefined(entry.minify) ? entry.minify : minify : void 0,
159
+ format,
160
+ banner: entry.banner,
161
+ footer: entry.footer,
162
+ intro: entry.intro,
163
+ outro: entry.outro,
164
+ name: entry.name,
165
+ globals: entry.globals,
166
+ extend: entry.extend,
167
+ plugins: entry.paths ? [outputPaths(entry.paths)] : void 0
168
+ };
169
+ const entryOptions = {
170
+ ...entryInput,
171
+ ...entryOutput,
172
+ externals: entryInput.external
173
+ };
174
+ const entryStats = {
175
+ cwd: cwdir,
176
+ path: outputRawPath,
177
+ size: 0,
178
+ buildTime: entryStart,
179
+ format: isChunk ? format : "dts",
180
+ logs: buildLogs
181
+ };
182
+ await hooks?.["build:entry:start"]?.(entryOptions, entryStats);
183
+ const bundle = await rolldown(entryInput);
184
+ if (isChunk) await bundle.write(entryOutput);
185
+ else {
186
+ const generated = await bundle.generate(entryOutput);
187
+ await write(outputResolvePath, generated.output[0].code);
188
+ }
189
+ const stats = await stat(outputResolvePath);
190
+ entryStats.size = stats.size;
191
+ entryStats.buildTime = Date.now() - entryStart;
192
+ entryStats.logs = buildLogs;
193
+ buildStats.files.push(entryStats);
194
+ buildStats.size = buildStats.size + stats.size;
195
+ logEntryStats(entryStats);
196
+ await hooks?.["build:entry:end"]?.(entryOptions, entryStats);
197
+ }
198
+ if (entry.copy) {
199
+ const inputResolvePath = resolve(cwdir, entry.copy);
200
+ const outputRawPath = parseOutputPath(entry.output) || getOutputPath(outDir, entry.copy, { extension: "original" });
201
+ const outputResolvePath = resolve(cwdir, outputRawPath);
202
+ await copy(inputResolvePath, outputResolvePath, {
203
+ recursive: entry.recursive || true,
204
+ filter: entry.filter
205
+ }).catch(error);
206
+ const stats = await stat(outputResolvePath);
207
+ let totalSize = 0;
208
+ if (!stats.isDirectory()) totalSize = stats.size;
209
+ else {
210
+ const files = await readdir(outputResolvePath);
211
+ for (const file of files) {
212
+ const filePath = resolve(outputResolvePath, file);
213
+ const fileStat = await stat(filePath);
214
+ totalSize = totalSize + fileStat.size;
215
+ }
216
+ }
217
+ const entryStats = {
218
+ cwd: cwdir,
219
+ path: outputRawPath,
220
+ size: totalSize,
221
+ buildTime: Date.now() - entryStart,
222
+ format: "copy",
223
+ logs: []
224
+ };
225
+ buildStats.files.push(entryStats);
226
+ buildStats.size = buildStats.size + stats.size;
227
+ logEntryStats(entryStats);
228
+ }
229
+ if (entry.template && entry.output) {
230
+ const outputRawPath = parseOutputPath(entry.output);
231
+ const outputResolvePath = resolve(cwdir, outputRawPath);
232
+ await write(outputResolvePath, entry.template);
233
+ const stats = await stat(outputResolvePath);
234
+ const entryStats = {
235
+ cwd: cwdir,
236
+ path: outputRawPath,
237
+ size: stats.size,
238
+ buildTime: Date.now() - entryStart,
239
+ format: "tmp",
240
+ logs: []
241
+ };
242
+ buildStats.files.push(entryStats);
243
+ buildStats.size = buildStats.size + stats.size;
244
+ logEntryStats(entryStats);
245
+ }
246
+ }
247
+ buildStats.buildTime = Date.now() - start;
248
+ }
249
+ await hooks?.["build:end"]?.(options, buildStats);
250
+ return buildStats;
251
+ }
252
+
253
+ //#endregion
254
+ export { build };