@hypernym/bundler 0.1.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.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Ivo Dolenc, Hypernym Studio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Bundler
2
+
3
+ ESM & TS module bundler.
4
+
5
+ <sub><a href="https://github.com/hypernym-studio/bundler">Repository</a> | <a href="https://www.npmjs.com/package/@hypernym/bundler">Package</a> | <a href="https://github.com/hypernym-studio/bundler/releases">Releases</a> | <a href="https://github.com/hypernym-studio/bundler/discussions">Discussions</a></sub>
6
+
7
+ ```sh
8
+ npm i -D @hypernym/bundler
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - Powered by Rollup
14
+ - Allows advanced customization
15
+ - Provides a powerful hooking system
16
+ - Exports fully optimized code
17
+ - Follows modern practice
18
+ - Super easy to use
19
+
20
+ ## Quick Start
21
+
22
+ 1. Create a `bundler.config.ts` file at the root of your project:
23
+
24
+ > **Note**
25
+ > Configuration also accepts `.js`, `.mjs`, `.ts`, `.mts` formats.
26
+
27
+ ```ts
28
+ // bundler.config.ts
29
+
30
+ import { defineConfig } from '@hypernym/bundler'
31
+
32
+ export default defineConfig({
33
+ // ...
34
+ })
35
+ ```
36
+
37
+ 2. Specify the bundle's entry points:
38
+
39
+ ```ts
40
+ // bundler.config.ts
41
+
42
+ import { defineConfig } from '@hypernym/bundler'
43
+
44
+ export default defineConfig({
45
+ entries: [
46
+ { input: './src/index.ts' },
47
+ { types: './src/types/index.ts' },
48
+ {
49
+ input: './src/utils/index.ts',
50
+ plugins: {
51
+ esbuild: { minify: true },
52
+ },
53
+ },
54
+ // ...
55
+ ],
56
+ })
57
+ ```
58
+
59
+ 3. Build via command:
60
+
61
+ ```sh
62
+ npx hyperbundler
63
+ ```
64
+
65
+ ## Options
66
+
67
+ ### outDir
68
+
69
+ - Type: `string`
70
+ - Default: `dist`
71
+
72
+ Specifies the output directory for production bundle.
73
+
74
+ ```ts
75
+ // bundler.config.ts
76
+
77
+ export default defineConfig({
78
+ outDir: 'output',
79
+ })
80
+ ```
81
+
82
+ ### Custom Config
83
+
84
+ Set a custom config path via the CLI command:
85
+
86
+ ```sh
87
+ npx hyperbundler --config my.config.js
88
+ ```
89
+
90
+ ## Community
91
+
92
+ Feel free to use the official [discussions](https://github.com/hypernym-studio/bundler/discussions) for any additional questions.
93
+
94
+ ## License
95
+
96
+ Developed in 🇭🇷 Croatia
97
+
98
+ Released under the [MIT](LICENSE.txt) license.
99
+
100
+ © Hypernym Studio
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env node
2
+ import process, { stdout, cwd } from 'node:process';
3
+ import { createArgs } from '@hypernym/args';
4
+ import { readFile, stat } from 'node:fs/promises';
5
+ import { resolve, parse } from 'node:path';
6
+ import { exists } from '@hypernym/utils/node';
7
+ import { dim, magenta, red, cyan, green } from '@hypernym/colors';
8
+ import { build as build$1, transform } from 'esbuild';
9
+ import { createSpinner } from '@hypernym/spinner';
10
+ import { isObject } from '@hypernym/utils';
11
+ import { rollup } from 'rollup';
12
+ import { getLogFilter } from 'rollup/getLogFilter';
13
+ import _replace from '@rollup/plugin-replace';
14
+ import _json from '@rollup/plugin-json';
15
+ import _resolve from '@rollup/plugin-node-resolve';
16
+ import { dts } from 'rollup-plugin-dts';
17
+ import { createFilter } from '@rollup/pluginutils';
18
+
19
+ const externals = [
20
+ /^node:/,
21
+ /^@types/,
22
+ /^@rollup/,
23
+ /^@hypernym/,
24
+ /^rollup/
25
+ ];
26
+
27
+ const name = "bundler";
28
+ const version = `0.1.0`;
29
+
30
+ const cl = console.log;
31
+ const log = (...args) => {
32
+ let length = args.length + 2;
33
+ const cols = stdout.columns || 80;
34
+ const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
35
+ for (const arg of args) {
36
+ length = length + arg.replace(/\u001b\[.*?m/g, "").length;
37
+ }
38
+ const repeatLength = cols <= length + time.length ? 0 : cols - (length + time.length);
39
+ return cl(...args, " ".repeat(repeatLength), dim(time));
40
+ };
41
+ const logger = {
42
+ exit: (message) => {
43
+ cl();
44
+ log(dim(name), dim(version));
45
+ log(magenta(name), message);
46
+ cl();
47
+ return process.exit(1);
48
+ }
49
+ };
50
+
51
+ function error(err) {
52
+ log(red(name), "Something went wrong...");
53
+ console.error(err);
54
+ return process.exit(1);
55
+ }
56
+
57
+ function formatMs(ms) {
58
+ const s = 1e3;
59
+ const m = s * 60;
60
+ const h = m * 60;
61
+ const msAbs = Math.abs(ms);
62
+ if (msAbs >= h)
63
+ return `${(ms / h).toFixed(2)}h`;
64
+ if (msAbs >= m)
65
+ return `${(ms / m).toFixed(2)}m`;
66
+ if (msAbs >= s)
67
+ return `${(ms / s).toFixed(2)}s`;
68
+ return `${ms}ms`;
69
+ }
70
+
71
+ function formatBytes(bytes) {
72
+ const decimals = 2;
73
+ const units = ["B", "KB", "MB", "GB", "TB"];
74
+ if (bytes === 0)
75
+ return `0 B`;
76
+ const k = 1024;
77
+ const dm = decimals;
78
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
79
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${units[i]}`;
80
+ }
81
+
82
+ function getOutputPath(outDir, input, types = false) {
83
+ const _input = input.startsWith("./") ? input.slice(2) : input;
84
+ let output = _input.replace(_input.split("/")[0], outDir);
85
+ const ts = types ? "d.ts" : "mjs";
86
+ const mts = types ? "d.mts" : "mjs";
87
+ const cts = types ? "d.cts" : "cjs";
88
+ if (output.endsWith(".ts"))
89
+ output = `${output.slice(0, -2)}${ts}`;
90
+ if (output.endsWith(".mts"))
91
+ output = `${output.slice(0, -3)}${mts}`;
92
+ if (output.endsWith(".cts"))
93
+ output = `${output.slice(0, -3)}${cts}`;
94
+ if (outDir.startsWith("./") || outDir.startsWith("../"))
95
+ return output;
96
+ return `./${output}`;
97
+ }
98
+
99
+ async function loadConfig(filePath, defaults) {
100
+ const result = await build$1({
101
+ entryPoints: [filePath],
102
+ bundle: true,
103
+ write: false,
104
+ format: "esm",
105
+ target: "esnext",
106
+ packages: "external"
107
+ });
108
+ const code = result.outputFiles[0].text;
109
+ const buffer = Buffer.from(code).toString("base64");
110
+ const content = await import(`data:text/javascript;base64,${buffer}`);
111
+ const config = {
112
+ ...defaults,
113
+ ...content.default
114
+ };
115
+ return config;
116
+ }
117
+ async function createConfigLoader(cwd, args) {
118
+ const pkgPath = resolve(cwd, "package.json");
119
+ const pkg = await readFile(pkgPath, "utf-8").catch(error);
120
+ const { dependencies } = JSON.parse(pkg);
121
+ const warnMessage = `Missing required configuration. To start bundling, add the ${cyan(
122
+ `'bundler.config.{js,mjs,ts,mts}'`
123
+ )} file to the project's root.`;
124
+ const defaults = {
125
+ externals: [...Object.keys(dependencies || {}), ...externals],
126
+ entries: []
127
+ };
128
+ if (args.config) {
129
+ const path = resolve(cwd, args.config);
130
+ const isConfig = await exists(path);
131
+ if (isConfig)
132
+ return await loadConfig(path, defaults);
133
+ else
134
+ return logger.exit(warnMessage);
135
+ }
136
+ const configName = "bundler.config";
137
+ const configExts = [".ts", ".js", ".mts", ".mjs"];
138
+ for (const ext of configExts) {
139
+ const path = resolve(cwd, `${configName}${ext}`);
140
+ const isConfig = await exists(path);
141
+ if (isConfig)
142
+ return await loadConfig(path, defaults);
143
+ }
144
+ return logger.exit(warnMessage);
145
+ }
146
+
147
+ function esbuild(options) {
148
+ const isJs = /\.(?:[mc]?js|jsx)$/;
149
+ const filter = createFilter(/\.([cm]?ts|[jt]sx)$/);
150
+ return {
151
+ name: "esbuild",
152
+ resolveId(id, importer, options2) {
153
+ if (isJs.test(id) && importer) {
154
+ return this.resolve(id.replace(/js(x?)$/, "ts$1"), importer, options2);
155
+ }
156
+ return null;
157
+ },
158
+ async transform(code, id) {
159
+ if (!filter(id))
160
+ return null;
161
+ const result = await transform(code, {
162
+ loader: "default",
163
+ ...options,
164
+ sourcefile: id.replace(/\.[cm]ts/, ".ts")
165
+ });
166
+ return {
167
+ code: result.code,
168
+ map: result.map || null
169
+ };
170
+ },
171
+ async renderChunk(code, { fileName }) {
172
+ if (!options?.minify)
173
+ return null;
174
+ if (/\.d\.(c|m)?tsx?$/.test(fileName))
175
+ return null;
176
+ const result = await transform(code, {
177
+ ...options,
178
+ sourcefile: fileName,
179
+ minify: true
180
+ });
181
+ return {
182
+ code: result.code,
183
+ map: result.map || null
184
+ };
185
+ }
186
+ };
187
+ }
188
+
189
+ const replacePlugin = _replace.default ?? _replace;
190
+ const jsonPlugin = _json.default ?? _json;
191
+ const resolvePlugin = _resolve.default ?? _resolve;
192
+ async function build(cwd, options) {
193
+ const { outDir = "dist", hooks } = options;
194
+ let start = 0;
195
+ const buildStats = {
196
+ cwd,
197
+ size: 0,
198
+ buildTime: 0,
199
+ files: []
200
+ };
201
+ if (hooks?.["build:before"])
202
+ await hooks["build:before"](options);
203
+ if (options.entries) {
204
+ start = Date.now();
205
+ for (const entry of options.entries) {
206
+ const entryStart = Date.now();
207
+ const logFilter = getLogFilter(entry.logFilter || []);
208
+ if ("input" in entry) {
209
+ const { input, externals, plugins, banner, footer } = entry;
210
+ const buildLogs = [];
211
+ const _output = getOutputPath(outDir, input);
212
+ let _format = "esm";
213
+ if (_output.endsWith(".cjs"))
214
+ _format = "cjs";
215
+ const output = entry.output || _output;
216
+ const format = entry.format || _format;
217
+ const defaultPlugins = [esbuild(plugins?.esbuild)];
218
+ if (plugins?.json) {
219
+ const jsonOptions = isObject(plugins.json) ? plugins.json : void 0;
220
+ defaultPlugins.push(jsonPlugin(jsonOptions));
221
+ }
222
+ if (plugins?.replace) {
223
+ defaultPlugins.unshift(
224
+ replacePlugin({
225
+ true: true,
226
+ ...plugins.replace
227
+ })
228
+ );
229
+ }
230
+ if (plugins?.resolve) {
231
+ const resolveOptions = isObject(plugins.resolve) ? plugins.resolve : void 0;
232
+ defaultPlugins.unshift(resolvePlugin(resolveOptions));
233
+ }
234
+ const builder = await rollup({
235
+ input: resolve(cwd, input),
236
+ external: externals || options.externals,
237
+ plugins: defaultPlugins,
238
+ onLog: (level, log) => {
239
+ if (logFilter(log))
240
+ buildLogs.push({ level, log });
241
+ }
242
+ });
243
+ await builder.write({
244
+ file: resolve(cwd, output),
245
+ format,
246
+ banner,
247
+ footer
248
+ });
249
+ const stats = await stat(resolve(cwd, output));
250
+ buildStats.files.push({
251
+ path: output,
252
+ size: stats.size,
253
+ buildTime: Date.now() - entryStart,
254
+ format,
255
+ logs: buildLogs
256
+ });
257
+ buildStats.size = buildStats.size + stats.size;
258
+ }
259
+ if ("types" in entry) {
260
+ const { types, plugins } = entry;
261
+ const buildLogs = [];
262
+ const _output = getOutputPath(outDir, types, true);
263
+ let _format = "esm";
264
+ if (_output.endsWith(".d.cts"))
265
+ _format = "cjs";
266
+ const output = entry.output || _output;
267
+ const format = entry.format || _format;
268
+ const builder = await rollup({
269
+ input: resolve(cwd, types),
270
+ plugins: [dts(plugins?.dts)],
271
+ onLog: (level, log) => {
272
+ if (logFilter(log))
273
+ buildLogs.push({ level, log });
274
+ }
275
+ });
276
+ await builder.write({
277
+ file: resolve(cwd, output),
278
+ format
279
+ });
280
+ const stats = await stat(resolve(cwd, output));
281
+ buildStats.files.push({
282
+ path: output,
283
+ size: stats.size,
284
+ buildTime: Date.now() - entryStart,
285
+ format,
286
+ logs: buildLogs
287
+ });
288
+ buildStats.size = buildStats.size + stats.size;
289
+ }
290
+ }
291
+ buildStats.buildTime = Date.now() - start;
292
+ }
293
+ if (hooks?.["build:done"])
294
+ await hooks["build:done"](options);
295
+ return buildStats;
296
+ }
297
+
298
+ async function createBuilder(cwd, args, options) {
299
+ const spinner = createSpinner();
300
+ cl();
301
+ log(dim(name), dim(version));
302
+ log(cyan(name), `Bundling started...`);
303
+ spinner.start({
304
+ message: `Transforming modules ${green("for production...")}`
305
+ });
306
+ return await build(cwd, options).then((stats) => {
307
+ spinner.stop({
308
+ message: `Modules transformation is ${green("done!")}`,
309
+ template: (mark, message) => {
310
+ const temp = `${mark}${message}`;
311
+ const cols = stdout.columns || 80;
312
+ const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
313
+ const length = (
314
+ // eslint-disable-next-line no-control-regex
315
+ temp.replace(/\u001b\[.*?m/g, "").length + time.length + 1
316
+ );
317
+ const repeatLength = cols <= length ? 0 : cols - length;
318
+ return temp + " ".repeat(repeatLength) + dim(time);
319
+ }
320
+ });
321
+ const check = green("\u2714");
322
+ const info = cyan("i");
323
+ const buildTime = green(formatMs(stats.buildTime));
324
+ const buildSize = green(formatBytes(stats.size));
325
+ const modules = green(stats.files.length);
326
+ const longestPath = Math.max(...stats.files.map((v) => v.path.length + 1));
327
+ const longestTime = Math.max(
328
+ ...stats.files.map((v) => formatMs(v.buildTime).length)
329
+ );
330
+ const longestSize = Math.max(
331
+ ...stats.files.map((v) => formatBytes(v.size).length)
332
+ );
333
+ log(check, `Bundling completed in ${buildTime}`);
334
+ log(check, `${modules} modules transformed. Total size is ${buildSize}`);
335
+ log(info, "Individual stats per module");
336
+ for (const file of stats.files) {
337
+ let format = file.format;
338
+ const base = parse(file.path).base;
339
+ const path = file.path.replace(base, "");
340
+ if (format.includes("system"))
341
+ format = "sys";
342
+ if (format === "commonjs")
343
+ format = "cjs";
344
+ if (format === "module")
345
+ format = "esm";
346
+ if (base.includes(".d."))
347
+ format = "dts";
348
+ if (file.logs) {
349
+ for (const log2 of file.logs) {
350
+ cl(magenta("!"), magenta(log2.log.message));
351
+ }
352
+ }
353
+ log(
354
+ info,
355
+ dim("\u251C\u2500"),
356
+ dim(path) + cyan(base),
357
+ " ".padEnd(longestPath - (path.length + base.length)),
358
+ dim(format.padStart(5)),
359
+ dim("\u2502"),
360
+ dim(formatMs(file.buildTime).padStart(longestTime)),
361
+ dim("\u2502"),
362
+ dim(formatBytes(file.size).padStart(longestSize))
363
+ );
364
+ }
365
+ log(
366
+ check,
367
+ `Bundle is now fully generated and ready ${green("for production!")}`
368
+ );
369
+ }).catch((err) => {
370
+ spinner.stop({
371
+ mark: red("\u2716"),
372
+ message: `Modules transformation is ${red("interupted!")}`
373
+ });
374
+ log(red(name), "Something went wrong...");
375
+ console.error(err);
376
+ return process.exit(1);
377
+ });
378
+ }
379
+
380
+ async function main() {
381
+ const cwd$1 = cwd();
382
+ const args = createArgs({
383
+ alias: { config: "c" }
384
+ });
385
+ const config = await createConfigLoader(cwd$1, args);
386
+ await createBuilder(cwd$1, args, config);
387
+ }
388
+ main().catch(error);
package/dist/index.mjs ADDED
@@ -0,0 +1,12 @@
1
+ const externals = [
2
+ /^node:/,
3
+ /^@types/,
4
+ /^@rollup/,
5
+ /^@hypernym/,
6
+ /^rollup/
7
+ ];
8
+ function defineConfig(options) {
9
+ return options;
10
+ }
11
+
12
+ export { defineConfig, externals };
@@ -0,0 +1,76 @@
1
+ import { OutputOptions } from 'rollup';
2
+ import { RollupReplaceOptions } from '@rollup/plugin-replace';
3
+ import { RollupJsonOptions } from '@rollup/plugin-json';
4
+ import { RollupNodeResolveOptions } from '@rollup/plugin-node-resolve';
5
+ import { TransformOptions } from 'esbuild';
6
+ import { Options as Options$1 } from 'rollup-plugin-dts';
7
+
8
+ interface BuildPlugins {
9
+ esbuild?: TransformOptions;
10
+ dts?: Options$1;
11
+ resolve?: RollupNodeResolveOptions | true;
12
+ json?: RollupJsonOptions | true;
13
+ replace?: RollupReplaceOptions;
14
+ }
15
+
16
+ interface Entries {
17
+ output?: string;
18
+ format?: OutputOptions['format'];
19
+ externals?: (string | RegExp)[];
20
+ logFilter?: string[];
21
+ }
22
+ interface EntriesInput extends Entries {
23
+ input: string;
24
+ banner?: OutputOptions['banner'];
25
+ footer?: OutputOptions['footer'];
26
+ plugins?: BuildPlugins;
27
+ }
28
+ interface EntriesTypes extends Entries {
29
+ types: string;
30
+ plugins?: Pick<BuildPlugins, 'dts'>;
31
+ }
32
+ type EntriesOptions = EntriesInput | EntriesTypes;
33
+
34
+ interface BuildHooks {
35
+ /**
36
+ * Called just before bundling started.
37
+ */
38
+ 'build:before'?: (options?: Options) => void | Promise<void>;
39
+ /**
40
+ * Called right after bundling is complete.
41
+ */
42
+ 'build:done'?: (options?: Options) => void | Promise<void>;
43
+ }
44
+
45
+ interface Options {
46
+ /**
47
+ * Specifies the bundle's entry points.
48
+ *
49
+ * It allows you to manually set all build entries and adjust options for each one individually.
50
+ */
51
+ entries: EntriesOptions[];
52
+ /**
53
+ * Specifies the output directory for production bundle.
54
+ *
55
+ * @default 'dist'
56
+ */
57
+ outDir?: string;
58
+ /**
59
+ * Specifies the module IDs, or regular expressions to match module IDs,
60
+ * that should remain external to the bundle.
61
+ *
62
+ * @default [/^node:/, /^@types/, /^@rollup/, /^@hypernym/, /^rollup/, ...pkg.dependencies]
63
+ */
64
+ externals?: (string | RegExp)[];
65
+ /**
66
+ * Provides a powerful hooking system to further expand build mode.
67
+ *
68
+ * @default undefined
69
+ */
70
+ hooks?: BuildHooks;
71
+ }
72
+
73
+ declare const externals: RegExp[];
74
+ declare function defineConfig(options: Options): Options;
75
+
76
+ export { defineConfig, externals };
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@hypernym/bundler",
3
+ "version": "0.1.0",
4
+ "author": "Hypernym Studio",
5
+ "description": "ESM & TS module bundler.",
6
+ "license": "MIT",
7
+ "repository": "hypernym-studio/bundler",
8
+ "homepage": "https://github.com/hypernym-studio/bundler",
9
+ "funding": "https://github.com/sponsors/ivodolenc",
10
+ "type": "module",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/types/index.d.ts",
14
+ "import": "./dist/index.mjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "keywords": [
21
+ "module",
22
+ "modules",
23
+ "bundling",
24
+ "javascript",
25
+ "typescript",
26
+ "bundler",
27
+ "builder",
28
+ "package",
29
+ "bundle",
30
+ "types",
31
+ "build",
32
+ "esm",
33
+ "dts"
34
+ ],
35
+ "bin": {
36
+ "hyperbundler": "./dist/bin/index.mjs"
37
+ },
38
+ "scripts": {
39
+ "build": "tsx src/bin/index.ts",
40
+ "lint": "ESLINT_USE_FLAT_CONFIG=true eslint -c .config/eslint.config.js .",
41
+ "lint:fix": "ESLINT_USE_FLAT_CONFIG=true eslint -c .config/eslint.config.js --fix .",
42
+ "format": "prettier --config .config/prettier.config.js --write .",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "peerDependencies": {
46
+ "@types/node": ">=20.0.0",
47
+ "typescript": ">=5.0.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "@types/node": {
51
+ "optional": true
52
+ },
53
+ "typescript": {
54
+ "optional": true
55
+ }
56
+ },
57
+ "dependencies": {
58
+ "@hypernym/args": "^0.2.0",
59
+ "@hypernym/colors": "^1.0.0",
60
+ "@hypernym/spinner": "^0.1.0",
61
+ "@hypernym/utils": "^2.0.2",
62
+ "@rollup/plugin-json": "^6.0.1",
63
+ "@rollup/plugin-node-resolve": "^15.2.3",
64
+ "@rollup/plugin-replace": "^5.0.3",
65
+ "esbuild": "^0.19.4",
66
+ "rollup": "^4.0.2",
67
+ "rollup-plugin-dts": "^6.1.0"
68
+ },
69
+ "devDependencies": {
70
+ "@hypernym/eslint-config": "^2.0.1",
71
+ "@hypernym/prettier-config": "^2.0.1",
72
+ "@hypernym/tsconfig": "^1.1.0",
73
+ "@types/node": "^20.8.4",
74
+ "eslint": "^8.51.0",
75
+ "prettier": "^3.0.3",
76
+ "tsx": "^3.13.0",
77
+ "typescript": "^5.2.2"
78
+ },
79
+ "engines": {
80
+ "node": ">=v18.0.0"
81
+ }
82
+ }