@d1g1tal/tsbuild 1.8.1 → 1.8.3
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/CHANGELOG.md +23 -0
- package/dist/{GWNROQXR.js → UM2SFHAT.js} +97 -56
- package/dist/tsbuild.js +2 -2
- package/dist/type-script-project.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
## [1.8.3](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.2...v1.8.3) (2026-04-11)
|
|
2
|
+
|
|
3
|
+
### Performance Improvements
|
|
4
|
+
|
|
5
|
+
* **core:** optimize build performance and decrease startup time (5cc35a8e0c6acc45dff38f6186e9f5b8f59ee8bf)
|
|
6
|
+
- use sets instead of arrays for faster lookups
|
|
7
|
+
- replace string concatenation with array joins
|
|
8
|
+
- replace object.keys with for-in loops
|
|
9
|
+
- cache regex patterns and avoid repeated compilations
|
|
10
|
+
- dynamically import esbuild and watchr to reduce startup time
|
|
11
|
+
- replace map/reduce chains with single loops for better performance
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Miscellaneous Chores
|
|
15
|
+
|
|
16
|
+
* **deps:** update dependency @types/node to ^25.6.0 (a99b720acf5c2d3ed4116605e66fbd0f0174259f)
|
|
17
|
+
|
|
18
|
+
## [1.8.2](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.1...v1.8.2) (2026-04-09)
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **build:** add handling for modules where the export uses 'as' (d96f626e7329188e702cd32bd8ba028810647d06)
|
|
23
|
+
|
|
1
24
|
## [1.8.1](https://github.com/D1g1talEntr0py/tsbuild/compare/v1.8.0...v1.8.1) (2026-04-09)
|
|
2
25
|
|
|
3
26
|
### Bug Fixes
|
|
@@ -139,9 +139,6 @@ var Files = class _Files {
|
|
|
139
139
|
}
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
-
// src/type-script-project.ts
|
|
143
|
-
import { Watchr } from "@d1g1tal/watchr";
|
|
144
|
-
|
|
145
142
|
// src/text-formatter.ts
|
|
146
143
|
import { isatty } from "node:tty";
|
|
147
144
|
var { env = {}, platform = "" } = process;
|
|
@@ -204,6 +201,8 @@ var TextFormat = class {
|
|
|
204
201
|
};
|
|
205
202
|
|
|
206
203
|
// src/logger.ts
|
|
204
|
+
var LOG_1024 = Math.log(1024);
|
|
205
|
+
var ansiEscapePattern = /\x1b\[[0-9;]*m/g;
|
|
207
206
|
var isWrittenFiles = (data) => {
|
|
208
207
|
if (!Array.isArray(data)) {
|
|
209
208
|
return false;
|
|
@@ -231,7 +230,7 @@ var prettyBytes = (bytes) => {
|
|
|
231
230
|
if (bytes === 0) {
|
|
232
231
|
return { value: "0", unit: "B" };
|
|
233
232
|
}
|
|
234
|
-
const exp = ~~(Math.log(bytes) /
|
|
233
|
+
const exp = ~~(Math.log(bytes) / LOG_1024);
|
|
235
234
|
return { value: (bytes / Math.pow(1024, exp)).toFixed(2), unit: dataUnits[exp] };
|
|
236
235
|
};
|
|
237
236
|
var Logger = class _Logger {
|
|
@@ -255,7 +254,7 @@ var Logger = class _Logger {
|
|
|
255
254
|
* @param message The message to display in the header.
|
|
256
255
|
*/
|
|
257
256
|
static header(message) {
|
|
258
|
-
const innerWidth = message.replace(
|
|
257
|
+
const innerWidth = message.replace(ansiEscapePattern, "").length + 2;
|
|
259
258
|
console.log(TextFormat.cyan(`\u256D${"\u2500".repeat(innerWidth)}\u256E${newLine}\u2502 ${message} \u2502${newLine}\u2570${"\u2500".repeat(innerWidth)}\u256F`));
|
|
260
259
|
}
|
|
261
260
|
/**
|
|
@@ -283,8 +282,17 @@ var Logger = class _Logger {
|
|
|
283
282
|
if (visible.length === 0) {
|
|
284
283
|
return;
|
|
285
284
|
}
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
let maxNameLength = 0;
|
|
286
|
+
let maxDurationLength = 0;
|
|
287
|
+
for (let i = 0, length = visible.length; i < length; i++) {
|
|
288
|
+
const { name, duration } = visible[i];
|
|
289
|
+
if (name.length > maxNameLength) {
|
|
290
|
+
maxNameLength = name.length;
|
|
291
|
+
}
|
|
292
|
+
if (duration.length > maxDurationLength) {
|
|
293
|
+
maxDurationLength = duration.length;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
288
296
|
for (let i = 0, length = visible.length; i < length; i++) {
|
|
289
297
|
const { name, duration } = visible[i];
|
|
290
298
|
const prefix = i === length - 1 ? " \u2514\u2500" : " \u251C\u2500";
|
|
@@ -353,10 +361,24 @@ var Logger = class _Logger {
|
|
|
353
361
|
* @internal
|
|
354
362
|
*/
|
|
355
363
|
static files(files) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
364
|
+
let maxPathLength = 0;
|
|
365
|
+
let maxValueLength = 0;
|
|
366
|
+
let maxUnitLength = 0;
|
|
367
|
+
const formatted = [];
|
|
368
|
+
for (let i = 0, length = files.length; i < length; i++) {
|
|
369
|
+
const { path, size } = files[i];
|
|
370
|
+
const { value, unit } = prettyBytes(size);
|
|
371
|
+
if (path.length > maxPathLength) {
|
|
372
|
+
maxPathLength = path.length;
|
|
373
|
+
}
|
|
374
|
+
if (value.length > maxValueLength) {
|
|
375
|
+
maxValueLength = value.length;
|
|
376
|
+
}
|
|
377
|
+
if (unit.length > maxUnitLength) {
|
|
378
|
+
maxUnitLength = unit.length;
|
|
379
|
+
}
|
|
380
|
+
formatted.push({ path, value, unit });
|
|
381
|
+
}
|
|
360
382
|
for (let i = 0, length = formatted.length; i < length; i++) {
|
|
361
383
|
const { path, value, unit } = formatted[i];
|
|
362
384
|
const paddedPath = path.padEnd(maxPathLength);
|
|
@@ -536,17 +558,13 @@ var DeclarationProcessor = class _DeclarationProcessor {
|
|
|
536
558
|
function createNamespaceImport(fileId) {
|
|
537
559
|
let importName = inlineImports.get(fileId);
|
|
538
560
|
if (importName === void 0) {
|
|
539
|
-
|
|
561
|
+
const chars = [];
|
|
540
562
|
for (let i = 0; i < fileId.length; i++) {
|
|
541
563
|
const char = fileId[i];
|
|
542
564
|
const code2 = char.charCodeAt(0);
|
|
543
|
-
|
|
544
|
-
sanitized += char;
|
|
545
|
-
} else {
|
|
546
|
-
sanitized += "_";
|
|
547
|
-
}
|
|
565
|
+
chars.push(code2 >= 97 && code2 <= 122 || code2 >= 65 && code2 <= 90 || code2 >= 48 && code2 <= 57 || code2 === 95 || code2 === 36 ? char : "_");
|
|
548
566
|
}
|
|
549
|
-
importName = generateUniqueName(
|
|
567
|
+
importName = generateUniqueName(chars.join(""));
|
|
550
568
|
inlineImports.set(fileId, importName);
|
|
551
569
|
}
|
|
552
570
|
return importName;
|
|
@@ -1206,8 +1224,9 @@ var DeclarationBundler = class {
|
|
|
1206
1224
|
};
|
|
1207
1225
|
forEachChild2(sourceFile, visitQualified);
|
|
1208
1226
|
}
|
|
1209
|
-
const
|
|
1210
|
-
const
|
|
1227
|
+
const finalValueExportsSet = new Set(valueExports.map(exportsMapper));
|
|
1228
|
+
const finalValueExports = [...finalValueExportsSet];
|
|
1229
|
+
const finalTypeExports = [...new Set(typeExports.map(exportsMapper).filter((t) => !finalValueExportsSet.has(t)))];
|
|
1211
1230
|
return { code: magic.toString(), externalImports, typeExports: finalTypeExports, valueExports: finalValueExports };
|
|
1212
1231
|
}
|
|
1213
1232
|
/**
|
|
@@ -1282,8 +1301,8 @@ var DeclarationBundler = class {
|
|
|
1282
1301
|
}
|
|
1283
1302
|
}
|
|
1284
1303
|
const uniqueTypeReferences = [...typeReferencesSet];
|
|
1285
|
-
const
|
|
1286
|
-
const
|
|
1304
|
+
const finalValueExportsSet = new Set(allValueExports);
|
|
1305
|
+
const finalValueExports = [...finalValueExportsSet];
|
|
1287
1306
|
const finalTypeExports = [...new Set(allTypeExports.filter((typeExport) => !finalValueExportsSet.has(typeExport)))];
|
|
1288
1307
|
const outputParts = [];
|
|
1289
1308
|
if (uniqueFileReferences.length > 0) {
|
|
@@ -1519,9 +1538,8 @@ async function resolvePlugins(plugins, projectDir) {
|
|
|
1519
1538
|
}
|
|
1520
1539
|
|
|
1521
1540
|
// src/plugins/iife.ts
|
|
1522
|
-
import { basename as basename2, dirname as dirname2, join, relative, resolve as resolve2 } from "node:path";
|
|
1523
1541
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1524
|
-
import {
|
|
1542
|
+
import { basename as basename2, dirname as dirname2, join, resolve as resolve2 } from "node:path";
|
|
1525
1543
|
var textDecoder2 = new TextDecoder();
|
|
1526
1544
|
var jsExtension = ".js";
|
|
1527
1545
|
function iifePlugin(options) {
|
|
@@ -1570,32 +1588,44 @@ function extractEntryNames(entryPoints) {
|
|
|
1570
1588
|
}
|
|
1571
1589
|
return Object.keys(entryPoints);
|
|
1572
1590
|
}
|
|
1573
|
-
var
|
|
1574
|
-
var
|
|
1591
|
+
var exportRegex = /export\s*\{([^}]*)\};?/g;
|
|
1592
|
+
var exportAliasRegex = /^(\w+)\s+as\s+(\w+)$/;
|
|
1575
1593
|
function wrapAsIife(text, globalName) {
|
|
1576
|
-
const
|
|
1577
|
-
if (
|
|
1594
|
+
const exportIndex = text.lastIndexOf("export");
|
|
1595
|
+
if (exportIndex === -1) {
|
|
1578
1596
|
return text;
|
|
1579
1597
|
}
|
|
1580
|
-
|
|
1581
|
-
const
|
|
1582
|
-
|
|
1583
|
-
|
|
1598
|
+
exportRegex.lastIndex = exportIndex;
|
|
1599
|
+
const last = exportRegex.exec(text);
|
|
1600
|
+
if (!last) {
|
|
1601
|
+
return text;
|
|
1602
|
+
}
|
|
1603
|
+
const props = [];
|
|
1604
|
+
for (const raw of last[1].split(",")) {
|
|
1605
|
+
const trimmed = raw.trim();
|
|
1606
|
+
if (!trimmed) {
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
const m = exportAliasRegex.exec(trimmed);
|
|
1610
|
+
props.push(m ? `${m[2]}: ${m[1]}` : trimmed);
|
|
1611
|
+
}
|
|
1612
|
+
if (props.length === 0) {
|
|
1584
1613
|
return text;
|
|
1585
1614
|
}
|
|
1586
|
-
const assignment = globalName ? `globalThis.${globalName} = { ${
|
|
1587
|
-
const body = text.slice(0,
|
|
1588
|
-
const after = text.slice(
|
|
1615
|
+
const assignment = globalName ? `globalThis.${globalName} = { ${props.join(", ")} };` : `Object.assign(globalThis, { ${props.join(", ")} });`;
|
|
1616
|
+
const body = text.slice(0, last.index);
|
|
1617
|
+
const after = text.slice(last.index + last[0].length);
|
|
1589
1618
|
return `(() => {
|
|
1590
1619
|
${body}
|
|
1591
1620
|
${assignment}
|
|
1592
1621
|
})();${after}`;
|
|
1593
1622
|
}
|
|
1594
1623
|
async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourcemap) {
|
|
1624
|
+
const { build: esbuild } = await import("esbuild");
|
|
1595
1625
|
const fileContents = /* @__PURE__ */ new Map();
|
|
1596
|
-
for (const
|
|
1597
|
-
if (
|
|
1598
|
-
fileContents.set(
|
|
1626
|
+
for (const { path, contents } of outputFiles) {
|
|
1627
|
+
if (path.endsWith(jsExtension)) {
|
|
1628
|
+
fileContents.set(path, textDecoder2.decode(contents));
|
|
1599
1629
|
}
|
|
1600
1630
|
}
|
|
1601
1631
|
const validEntries = [];
|
|
@@ -1627,15 +1657,16 @@ async function buildIife(outputFiles, entryPointNames, outdir, globalName, sourc
|
|
|
1627
1657
|
));
|
|
1628
1658
|
const written = [];
|
|
1629
1659
|
const writes = [];
|
|
1660
|
+
const cwd = process.cwd();
|
|
1630
1661
|
for (const { outputFiles: iifeFiles } of results) {
|
|
1631
|
-
for (const
|
|
1632
|
-
if (
|
|
1633
|
-
const text = wrapAsIife(textDecoder2.decode(
|
|
1634
|
-
writes.push(writeFile3(
|
|
1635
|
-
written.push({ path: relative(
|
|
1662
|
+
for (const { path, contents } of iifeFiles) {
|
|
1663
|
+
if (path.endsWith(jsExtension)) {
|
|
1664
|
+
const text = wrapAsIife(textDecoder2.decode(contents), globalName);
|
|
1665
|
+
writes.push(writeFile3(path, text));
|
|
1666
|
+
written.push({ path: Paths.relative(cwd, path), size: Buffer.byteLength(text) });
|
|
1636
1667
|
} else {
|
|
1637
|
-
writes.push(writeFile3(
|
|
1638
|
-
written.push({ path: relative(
|
|
1668
|
+
writes.push(writeFile3(path, contents));
|
|
1669
|
+
written.push({ path: Paths.relative(cwd, path), size: contents.byteLength });
|
|
1639
1670
|
}
|
|
1640
1671
|
}
|
|
1641
1672
|
}
|
|
@@ -2022,8 +2053,9 @@ var FileManager = class {
|
|
|
2022
2053
|
return defaultEntryPoint in projectEntryPoints ? { [defaultEntryPoint]: projectEntryPoints[defaultEntryPoint] } : projectEntryPoints;
|
|
2023
2054
|
}
|
|
2024
2055
|
const result = {};
|
|
2056
|
+
const allowedEntryPoints = new Set(dtsEntryPoints);
|
|
2025
2057
|
for (const [name, path] of Object.entries(projectEntryPoints)) {
|
|
2026
|
-
if (
|
|
2058
|
+
if (allowedEntryPoints.has(name)) {
|
|
2027
2059
|
result[name] = path;
|
|
2028
2060
|
}
|
|
2029
2061
|
}
|
|
@@ -2287,7 +2319,12 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
|
|
|
2287
2319
|
}
|
|
2288
2320
|
}
|
|
2289
2321
|
}
|
|
2290
|
-
|
|
2322
|
+
let hasEntries = false;
|
|
2323
|
+
for (const _ in entryPoints) {
|
|
2324
|
+
hasEntries = true;
|
|
2325
|
+
break;
|
|
2326
|
+
}
|
|
2327
|
+
if (!hasEntries) {
|
|
2291
2328
|
const legacyPath = packageJson.module ?? packageJson.main;
|
|
2292
2329
|
if (legacyPath !== void 0) {
|
|
2293
2330
|
const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
|
|
@@ -2296,11 +2333,13 @@ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
|
|
|
2296
2333
|
}
|
|
2297
2334
|
}
|
|
2298
2335
|
}
|
|
2299
|
-
|
|
2336
|
+
for (const _ in entryPoints) {
|
|
2337
|
+
return entryPoints;
|
|
2338
|
+
}
|
|
2339
|
+
return void 0;
|
|
2300
2340
|
}
|
|
2301
2341
|
|
|
2302
2342
|
// src/type-script-project.ts
|
|
2303
|
-
import { build as esbuild2, formatMessages } from "esbuild";
|
|
2304
2343
|
import { performance as performance2 } from "node:perf_hooks";
|
|
2305
2344
|
import { sys as sys2, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
|
|
2306
2345
|
var globCharacters = /[*?\\[\]!].*$/;
|
|
@@ -2344,7 +2383,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2344
2383
|
return Files.empty(this.buildConfiguration.outDir);
|
|
2345
2384
|
}
|
|
2346
2385
|
async build() {
|
|
2347
|
-
Logger.header(`${tsLogo} tsbuild v${"1.8.
|
|
2386
|
+
Logger.header(`${tsLogo} tsbuild v${"1.8.3"}${this.configuration.compilerOptions.incremental && this.configuration.buildCache?.isValid() ? " [incremental]" : ""}`);
|
|
2348
2387
|
try {
|
|
2349
2388
|
const processes = [];
|
|
2350
2389
|
const filesWereEmitted = await this.typeCheck();
|
|
@@ -2375,7 +2414,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2375
2414
|
}
|
|
2376
2415
|
}
|
|
2377
2416
|
if (this.fileWatcher === void 0 || this.fileWatcher.isClosed()) {
|
|
2378
|
-
setImmediate(() => this.watch());
|
|
2417
|
+
setImmediate(() => void this.watch());
|
|
2379
2418
|
}
|
|
2380
2419
|
}
|
|
2381
2420
|
}
|
|
@@ -2414,6 +2453,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2414
2453
|
return emitted || !this.configuration.compilerOptions.declaration;
|
|
2415
2454
|
}
|
|
2416
2455
|
async transpile() {
|
|
2456
|
+
const { build: esbuild, formatMessages } = await import("esbuild");
|
|
2417
2457
|
const plugins = [outputPlugin()];
|
|
2418
2458
|
if (this.buildConfiguration.noExternal.length > 0) {
|
|
2419
2459
|
plugins.push(externalModulesPlugin({ dependencies: await this.getProjectDependencyPaths(), noExternal: this.buildConfiguration.noExternal }));
|
|
@@ -2442,7 +2482,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2442
2482
|
}
|
|
2443
2483
|
}
|
|
2444
2484
|
try {
|
|
2445
|
-
const { warnings, errors, metafile: { outputs } } = await
|
|
2485
|
+
const { warnings, errors, metafile: { outputs } } = await esbuild({
|
|
2446
2486
|
format,
|
|
2447
2487
|
plugins,
|
|
2448
2488
|
define,
|
|
@@ -2506,7 +2546,8 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2506
2546
|
/**
|
|
2507
2547
|
* Watches for changes in the project files and rebuilds the project when changes are detected.
|
|
2508
2548
|
*/
|
|
2509
|
-
watch() {
|
|
2549
|
+
async watch() {
|
|
2550
|
+
const { Watchr } = await import("@d1g1tal/watchr");
|
|
2510
2551
|
const targets = [];
|
|
2511
2552
|
for (const path of this.configuration.include ?? [defaultSourceDirectory]) {
|
|
2512
2553
|
targets.push(Paths.absolute(this.directory, path.replace(globCharacters, "")));
|
|
@@ -2560,7 +2601,7 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2560
2601
|
Logger.info(`Rebuilding project: ${this.pendingChanges.length} file changes detected.`);
|
|
2561
2602
|
const rootNames = [...this.builderProgram.getProgram().getRootFileNames()];
|
|
2562
2603
|
for (const { event, path, nextPath } of this.pendingChanges) {
|
|
2563
|
-
if (nextPath !== void 0 && (event ===
|
|
2604
|
+
if (nextPath !== void 0 && (event === "rename" || event === "renameDir")) {
|
|
2564
2605
|
this.buildDependencies.delete(Paths.relative(this.directory, path));
|
|
2565
2606
|
this.buildDependencies.add(Paths.relative(this.directory, nextPath));
|
|
2566
2607
|
const index = rootNames.indexOf(path);
|
|
@@ -2569,9 +2610,9 @@ var _TypeScriptProject = class _TypeScriptProject {
|
|
|
2569
2610
|
}
|
|
2570
2611
|
} else {
|
|
2571
2612
|
const index = rootNames.indexOf(path);
|
|
2572
|
-
if (event ===
|
|
2613
|
+
if (event === "unlink" && index !== -1) {
|
|
2573
2614
|
rootNames.splice(index, 1);
|
|
2574
|
-
} else if (event ===
|
|
2615
|
+
} else if (event === "add" && index === -1) {
|
|
2575
2616
|
rootNames.push(path);
|
|
2576
2617
|
}
|
|
2577
2618
|
}
|
package/dist/tsbuild.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BuildError,
|
|
4
4
|
TypeScriptProject
|
|
5
|
-
} from "./
|
|
5
|
+
} from "./UM2SFHAT.js";
|
|
6
6
|
import "./JKGYA2AW.js";
|
|
7
7
|
|
|
8
8
|
// src/tsbuild.ts
|
|
@@ -30,7 +30,7 @@ if (help) {
|
|
|
30
30
|
process.exit(0);
|
|
31
31
|
}
|
|
32
32
|
if (version) {
|
|
33
|
-
console.log("1.8.
|
|
33
|
+
console.log("1.8.3");
|
|
34
34
|
process.exit(0);
|
|
35
35
|
}
|
|
36
36
|
var typeScriptOptions = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d1g1tal/tsbuild",
|
|
3
3
|
"author": "D1g1talEntr0py",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A fast, ESM-only TypeScript build tool combining the TypeScript API for type checking and declaration generation, esbuild for bundling, and SWC for decorator metadata.",
|
|
7
7
|
"homepage": "https://github.com/D1g1talEntr0py/tsbuild#readme",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@eslint/js": "^10.0.1",
|
|
53
|
-
"@types/node": "^25.
|
|
53
|
+
"@types/node": "^25.6.0",
|
|
54
54
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
55
55
|
"@typescript-eslint/parser": "^8.58.1",
|
|
56
56
|
"@vitest/coverage-v8": "^4.1.4",
|