@b9g/libuild 0.1.10 → 0.1.12
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 +6 -0
- package/package.json +1 -1
- package/src/cli.cjs +38 -2
- package/src/cli.js +38 -2
- package/src/libuild.cjs +437 -101
- package/src/libuild.js +445 -101
package/src/libuild.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
/// <reference types="./libuild.d.ts" />
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined")
|
|
6
|
+
return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
9
|
+
|
|
2
10
|
// src/libuild.ts
|
|
3
11
|
import * as FS3 from "fs/promises";
|
|
4
12
|
import * as Path3 from "path";
|
|
@@ -67,6 +75,21 @@ function externalEntrypointsPlugin(options) {
|
|
|
67
75
|
};
|
|
68
76
|
}
|
|
69
77
|
});
|
|
78
|
+
build3.onResolve({ filter: /^\.\.\/(?:src|bin)\// }, (args) => {
|
|
79
|
+
const withoutExt = args.path.replace(/\.(ts|js)$/, "");
|
|
80
|
+
const match = withoutExt.match(/^\.\.\/(?:src|bin)\/(.+)$/);
|
|
81
|
+
if (match) {
|
|
82
|
+
const entryName = match[1];
|
|
83
|
+
if (externalEntries.includes(entryName)) {
|
|
84
|
+
const dir = withoutExt.match(/^(\.\.\/(?:src|bin))\//)?.[1];
|
|
85
|
+
return {
|
|
86
|
+
path: `${dir}/${entryName}${outputExtension}`,
|
|
87
|
+
external: true
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return void 0;
|
|
92
|
+
});
|
|
70
93
|
}
|
|
71
94
|
};
|
|
72
95
|
}
|
|
@@ -92,27 +115,34 @@ function dtsPlugin(options) {
|
|
|
92
115
|
let TS;
|
|
93
116
|
try {
|
|
94
117
|
TS = await import("typescript");
|
|
95
|
-
} catch {
|
|
118
|
+
} catch (error) {
|
|
96
119
|
return;
|
|
97
120
|
}
|
|
98
121
|
const tsFiles = entryFiles.filter((file) => {
|
|
99
122
|
if (!file.endsWith(".ts"))
|
|
100
123
|
return false;
|
|
101
124
|
return options.entryPoints.some((entryPoint) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
try {
|
|
126
|
+
const fs = __require("fs");
|
|
127
|
+
const normalizedEntry = fs.realpathSync(Path2.resolve(entryPoint));
|
|
128
|
+
const normalizedFile = fs.realpathSync(Path2.resolve(file));
|
|
129
|
+
return normalizedEntry === normalizedFile;
|
|
130
|
+
} catch {
|
|
131
|
+
const normalizedEntry = Path2.resolve(entryPoint);
|
|
132
|
+
const normalizedFile = Path2.resolve(file);
|
|
133
|
+
return normalizedEntry === normalizedFile;
|
|
134
|
+
}
|
|
105
135
|
});
|
|
106
136
|
});
|
|
107
137
|
if (tsFiles.length === 0) {
|
|
108
138
|
return;
|
|
109
139
|
}
|
|
110
140
|
try {
|
|
141
|
+
await FS2.mkdir(options.outDir, { recursive: true });
|
|
111
142
|
const compilerOptions = {
|
|
112
143
|
declaration: true,
|
|
113
144
|
emitDeclarationOnly: true,
|
|
114
145
|
outDir: options.outDir,
|
|
115
|
-
rootDir: options.rootDir,
|
|
116
146
|
skipLibCheck: true,
|
|
117
147
|
esModuleInterop: true,
|
|
118
148
|
target: TS.ScriptTarget.ES2020,
|
|
@@ -187,6 +217,38 @@ ${content}`;
|
|
|
187
217
|
}
|
|
188
218
|
|
|
189
219
|
// src/libuild.ts
|
|
220
|
+
function generateRuntimeBanner(pkg) {
|
|
221
|
+
const prefersBun = pkg.engines?.bun !== void 0;
|
|
222
|
+
if (prefersBun) {
|
|
223
|
+
return '//bin/true; exec "$({ [ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] || true; } && command -v bun || command -v node)" "$0" "$@"';
|
|
224
|
+
} else {
|
|
225
|
+
return '//bin/true; exec "$([ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] && command -v bun || command -v node)" "$0" "$@"';
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function processJavaScriptExecutable(filePath, runtimeBanner) {
|
|
229
|
+
try {
|
|
230
|
+
const contents = await FS3.readFile(filePath, "utf8");
|
|
231
|
+
const lines = contents.split("\n");
|
|
232
|
+
let modified = false;
|
|
233
|
+
if (lines[0]?.startsWith("#!")) {
|
|
234
|
+
const existingShebang = lines[0];
|
|
235
|
+
if (existingShebang.includes("python") || existingShebang.includes("bash") || !existingShebang.includes("node") && !existingShebang.includes("bun") && !existingShebang.includes("sh")) {
|
|
236
|
+
console.warn(`\u26A0\uFE0F WARNING: ${filePath} has non-JavaScript shebang but is a JS file. Adding dual runtime support.`);
|
|
237
|
+
}
|
|
238
|
+
lines[0] = "#!/usr/bin/env sh";
|
|
239
|
+
lines.splice(1, 0, runtimeBanner);
|
|
240
|
+
modified = true;
|
|
241
|
+
} else {
|
|
242
|
+
lines.unshift("#!/usr/bin/env sh", runtimeBanner);
|
|
243
|
+
modified = true;
|
|
244
|
+
}
|
|
245
|
+
if (modified) {
|
|
246
|
+
await FS3.writeFile(filePath, lines.join("\n"));
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn(`\u26A0\uFE0F WARNING: Could not process executable ${filePath}: ${error.message}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
190
252
|
function isValidEntrypoint(filename) {
|
|
191
253
|
if (!filename.endsWith(".ts") && !filename.endsWith(".js"))
|
|
192
254
|
return false;
|
|
@@ -213,6 +275,22 @@ async function findEntrypoints(srcDir) {
|
|
|
213
275
|
return isValidEntrypoint(dirent.name);
|
|
214
276
|
}).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
|
|
215
277
|
}
|
|
278
|
+
async function findBinEntrypoints(binDir) {
|
|
279
|
+
try {
|
|
280
|
+
const files = await FS3.readdir(binDir, { withFileTypes: true });
|
|
281
|
+
return files.filter((dirent) => {
|
|
282
|
+
if (dirent.isDirectory()) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
return isValidEntrypoint(dirent.name);
|
|
286
|
+
}).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if (error.code === "ENOENT") {
|
|
289
|
+
return [];
|
|
290
|
+
}
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
216
294
|
function detectMainEntry(pkg, entries) {
|
|
217
295
|
function extractEntryFromPath(path) {
|
|
218
296
|
const match = path.match(/\.\/src\/([^.]+)/);
|
|
@@ -310,18 +388,38 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
|
|
|
310
388
|
}
|
|
311
389
|
return entryName ? !entries.includes(entryName) : false;
|
|
312
390
|
}
|
|
313
|
-
function generateExports(entries, mainEntry, options, existingExports = {}) {
|
|
391
|
+
async function generateExports(entries, mainEntry, options, existingExports = {}, distDir, allBinEntries = []) {
|
|
314
392
|
const exports = {};
|
|
315
393
|
const staleExports = [];
|
|
316
|
-
function createExportEntry(entry) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
394
|
+
async function createExportEntry(entry) {
|
|
395
|
+
if (entry.startsWith("bin/")) {
|
|
396
|
+
const binEntry = entry.replace("bin/", "");
|
|
397
|
+
const exportEntry = {
|
|
398
|
+
import: `./bin/${binEntry}.js`
|
|
399
|
+
};
|
|
400
|
+
if (distDir) {
|
|
401
|
+
const dtsPath = Path3.join(distDir, "bin", `${binEntry}.d.ts`);
|
|
402
|
+
if (await fileExists(dtsPath)) {
|
|
403
|
+
exportEntry.types = `./bin/${binEntry}.d.ts`;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return exportEntry;
|
|
407
|
+
} else {
|
|
408
|
+
const exportEntry = {
|
|
409
|
+
import: `./src/${entry}.js`
|
|
410
|
+
};
|
|
411
|
+
if (distDir) {
|
|
412
|
+
const dtsPath = Path3.join(distDir, "src", `${entry}.d.ts`);
|
|
413
|
+
const exists = await fileExists(dtsPath);
|
|
414
|
+
if (exists) {
|
|
415
|
+
exportEntry.types = `./src/${entry}.d.ts`;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (options.formats.cjs) {
|
|
419
|
+
exportEntry.require = `./src/${entry}.cjs`;
|
|
420
|
+
}
|
|
421
|
+
return exportEntry;
|
|
323
422
|
}
|
|
324
|
-
return exportEntry;
|
|
325
423
|
}
|
|
326
424
|
function expandExistingExport(existing, entryFromPath) {
|
|
327
425
|
if (typeof existing === "string") {
|
|
@@ -395,7 +493,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
|
|
|
395
493
|
}
|
|
396
494
|
}
|
|
397
495
|
if (!exports["."]) {
|
|
398
|
-
exports["."] = createExportEntry(mainEntry);
|
|
496
|
+
exports["."] = await createExportEntry(mainEntry);
|
|
399
497
|
} else {
|
|
400
498
|
exports["."] = expandExistingExport(exports["."], mainEntry);
|
|
401
499
|
}
|
|
@@ -404,7 +502,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
|
|
|
404
502
|
continue;
|
|
405
503
|
const key = `./${entry}`;
|
|
406
504
|
if (!exports[key]) {
|
|
407
|
-
exports[key] = createExportEntry(entry);
|
|
505
|
+
exports[key] = await createExportEntry(entry);
|
|
408
506
|
} else {
|
|
409
507
|
exports[key] = expandExistingExport(exports[key], entry);
|
|
410
508
|
}
|
|
@@ -442,67 +540,96 @@ function transformSrcToDist(value) {
|
|
|
442
540
|
}
|
|
443
541
|
return value;
|
|
444
542
|
}
|
|
445
|
-
async function validateBinPaths(value,
|
|
543
|
+
async function validateBinPaths(value, cwd, save, fieldName = "bin") {
|
|
446
544
|
if (typeof value === "string") {
|
|
447
|
-
await validateSingleBinPath(value, fieldName,
|
|
545
|
+
await validateSingleBinPath(value, fieldName, cwd, save);
|
|
448
546
|
} else if (typeof value === "object" && value !== null) {
|
|
449
547
|
for (const [key, val] of Object.entries(value)) {
|
|
450
548
|
if (typeof val === "string") {
|
|
451
|
-
await validateSingleBinPath(val, `${fieldName}.${key}`,
|
|
549
|
+
await validateSingleBinPath(val, `${fieldName}.${key}`, cwd, save);
|
|
452
550
|
}
|
|
453
551
|
}
|
|
454
552
|
}
|
|
455
553
|
}
|
|
456
|
-
async function validateSingleBinPath(binPath, fieldName,
|
|
457
|
-
if (
|
|
554
|
+
async function validateSingleBinPath(binPath, fieldName, cwd, save) {
|
|
555
|
+
if (save) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/") || binPath.startsWith("dist/bin/") || binPath.startsWith("./dist/bin/")) {
|
|
559
|
+
const fullPath2 = Path3.join(cwd, binPath);
|
|
560
|
+
const distExists = await fileExists(fullPath2);
|
|
561
|
+
if (distExists) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
458
564
|
let srcPath;
|
|
565
|
+
let sourceDir;
|
|
459
566
|
if (binPath.startsWith("./dist/src/")) {
|
|
460
567
|
srcPath = binPath.replace("./dist/src/", "src/");
|
|
568
|
+
sourceDir = "src";
|
|
461
569
|
} else if (binPath.startsWith("dist/src/")) {
|
|
462
570
|
srcPath = binPath.replace("dist/src/", "src/");
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
571
|
+
sourceDir = "src";
|
|
572
|
+
} else if (binPath.startsWith("./dist/bin/")) {
|
|
573
|
+
srcPath = binPath.replace("./dist/bin/", "bin/");
|
|
574
|
+
sourceDir = "bin";
|
|
575
|
+
} else if (binPath.startsWith("dist/bin/")) {
|
|
576
|
+
srcPath = binPath.replace("dist/bin/", "bin/");
|
|
577
|
+
sourceDir = "bin";
|
|
467
578
|
} else {
|
|
468
|
-
srcPath =
|
|
579
|
+
srcPath = binPath;
|
|
580
|
+
sourceDir = "src";
|
|
469
581
|
}
|
|
470
|
-
const basePath = srcPath.replace(/\.(js|cjs)$/, "");
|
|
471
|
-
const tsPath = Path3.join(
|
|
472
|
-
const jsPath = Path3.join(
|
|
582
|
+
const basePath = srcPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
583
|
+
const tsPath = Path3.join(cwd, basePath + ".ts");
|
|
584
|
+
const jsPath = Path3.join(cwd, basePath + ".js");
|
|
473
585
|
const srcExists = await fileExists(tsPath) || await fileExists(jsPath);
|
|
474
586
|
if (!srcExists) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
INCORRECT: "bin": {"tool": "dist/cli.js"}
|
|
480
|
-
|
|
481
|
-
Libuild workflow:
|
|
482
|
-
1. Point bin entries to src/ files
|
|
483
|
-
2. Run 'libuild build --save' to update package.json with dist/ paths
|
|
484
|
-
3. Set "private": true in your development package.json
|
|
485
|
-
|
|
486
|
-
If you need to include pre-built executable files, use the files field instead:
|
|
487
|
-
"files": ["scripts/my-tool.js"]`);
|
|
587
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" but neither the dist file nor corresponding src file exists.
|
|
588
|
+
|
|
589
|
+
Create "${srcPath}" and run 'libuild build --save' to update paths correctly.`);
|
|
590
|
+
return;
|
|
488
591
|
}
|
|
489
|
-
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to
|
|
592
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist yet.
|
|
490
593
|
|
|
491
|
-
libuild
|
|
492
|
-
|
|
594
|
+
Run 'libuild build' to create the dist files, or use 'libuild build --save' to update the path to "${srcPath}".`);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (binPath.startsWith("dist/") || binPath.startsWith("./dist/")) {
|
|
598
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" in dist/ directory.
|
|
493
599
|
|
|
494
|
-
|
|
495
|
-
Consider changing to: "${srcPath}" and running 'libuild build --save'`);
|
|
600
|
+
libuild expects bin entries to point to src/ files. Consider changing to the corresponding src/ path and using --save.`);
|
|
496
601
|
return;
|
|
497
602
|
}
|
|
498
|
-
|
|
603
|
+
const fullPath = Path3.join(cwd, binPath);
|
|
604
|
+
const pathExists = await fileExists(fullPath);
|
|
605
|
+
if (pathExists) {
|
|
499
606
|
return;
|
|
500
607
|
}
|
|
501
|
-
if (
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
608
|
+
if (binPath.startsWith("src/") || binPath.startsWith("./src/") || binPath.startsWith("bin/") || binPath.startsWith("./bin/")) {
|
|
609
|
+
let normalizedPath = binPath.startsWith("./") ? binPath.slice(2) : binPath;
|
|
610
|
+
if (normalizedPath.startsWith("src/")) {
|
|
611
|
+
const srcRelativePath = normalizedPath.replace("src/", "");
|
|
612
|
+
if (srcRelativePath.includes("/")) {
|
|
613
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which is in a subdirectory of src/.`);
|
|
614
|
+
console.warn(` libuild only auto-detects top-level src/ files as entrypoints.`);
|
|
615
|
+
console.warn(` Consider moving the file to the top-level src/ directory or use the bin/ directory for executables.`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const basePath = fullPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
619
|
+
const tsPath = basePath + ".ts";
|
|
620
|
+
const jsPath = basePath + ".js";
|
|
621
|
+
const tsExists = await fileExists(tsPath);
|
|
622
|
+
const jsExists = await fileExists(jsPath);
|
|
623
|
+
if (tsExists || jsExists) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
505
626
|
}
|
|
627
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist
|
|
628
|
+
|
|
629
|
+
libuild is ZERO-CONFIG - there is no libuild.config.js file!
|
|
630
|
+
Configuration comes from your package.json fields.
|
|
631
|
+
|
|
632
|
+
Use 'libuild build --save' to update package.json with correct dist/ paths automatically.`);
|
|
506
633
|
}
|
|
507
634
|
function transformBinPaths(value) {
|
|
508
635
|
if (typeof value === "string") {
|
|
@@ -512,10 +639,19 @@ function transformBinPaths(value) {
|
|
|
512
639
|
if (value.startsWith("dist/src/")) {
|
|
513
640
|
return value.replace("dist/", "");
|
|
514
641
|
}
|
|
642
|
+
if (value.startsWith("./dist/bin/")) {
|
|
643
|
+
return value.replace("./dist/", "");
|
|
644
|
+
}
|
|
645
|
+
if (value.startsWith("dist/bin/")) {
|
|
646
|
+
return value.replace("dist/", "");
|
|
647
|
+
}
|
|
515
648
|
if (value.startsWith("./src/")) {
|
|
516
649
|
return value.replace("./", "");
|
|
517
650
|
}
|
|
518
|
-
if (value.startsWith("
|
|
651
|
+
if (value.startsWith("./bin/")) {
|
|
652
|
+
return value.replace("./", "");
|
|
653
|
+
}
|
|
654
|
+
if (value.startsWith("src/") || value === "src" || value.startsWith("bin/") || value === "bin") {
|
|
519
655
|
return value;
|
|
520
656
|
}
|
|
521
657
|
return value;
|
|
@@ -560,7 +696,103 @@ function fixExportsForDist(obj) {
|
|
|
560
696
|
}
|
|
561
697
|
return obj;
|
|
562
698
|
}
|
|
563
|
-
function
|
|
699
|
+
async function setExecutablePermissions(filePath) {
|
|
700
|
+
try {
|
|
701
|
+
await FS3.chmod(filePath, 493);
|
|
702
|
+
} catch (error) {
|
|
703
|
+
console.warn(`\u26A0\uFE0F WARNING: Could not set executable permissions for ${filePath}: ${error.message}`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
async function makeFilesExecutable(pkg, cwd, allBinEntries) {
|
|
707
|
+
const filesToMakeExecutable = [];
|
|
708
|
+
if (pkg.bin) {
|
|
709
|
+
if (typeof pkg.bin === "string") {
|
|
710
|
+
filesToMakeExecutable.push(Path3.join(cwd, pkg.bin));
|
|
711
|
+
} else if (typeof pkg.bin === "object") {
|
|
712
|
+
for (const binPath of Object.values(pkg.bin)) {
|
|
713
|
+
if (typeof binPath === "string") {
|
|
714
|
+
filesToMakeExecutable.push(Path3.join(cwd, binPath));
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
for (const binEntryInfo of allBinEntries) {
|
|
720
|
+
const baseDir = binEntryInfo.source === "src" ? "dist/src/bin" : "dist/bin";
|
|
721
|
+
const jsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.js`);
|
|
722
|
+
const cjsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.cjs`);
|
|
723
|
+
if (!filesToMakeExecutable.includes(jsPath)) {
|
|
724
|
+
filesToMakeExecutable.push(jsPath);
|
|
725
|
+
}
|
|
726
|
+
if (!filesToMakeExecutable.includes(cjsPath)) {
|
|
727
|
+
filesToMakeExecutable.push(cjsPath);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
for (const filePath of filesToMakeExecutable) {
|
|
731
|
+
if (await fileExists(filePath)) {
|
|
732
|
+
await setExecutablePermissions(filePath);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function resolveWorkspaceDependencies(dependencies, cwd) {
|
|
737
|
+
if (!dependencies)
|
|
738
|
+
return void 0;
|
|
739
|
+
const resolved = {};
|
|
740
|
+
for (const [depName, depVersion] of Object.entries(dependencies)) {
|
|
741
|
+
if (depVersion.startsWith("workspace:")) {
|
|
742
|
+
const resolvedVersion = await resolveWorkspaceVersion(depName, depVersion, cwd);
|
|
743
|
+
resolved[depName] = resolvedVersion;
|
|
744
|
+
} else {
|
|
745
|
+
resolved[depName] = depVersion;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return resolved;
|
|
749
|
+
}
|
|
750
|
+
async function resolveWorkspaceVersion(packageName, workspaceSpec, cwd) {
|
|
751
|
+
try {
|
|
752
|
+
if (workspaceSpec === "workspace:*") {
|
|
753
|
+
const packageNameParts = packageName.replace("@", "").replace("/", "-");
|
|
754
|
+
const packageBaseName = packageName.split("/").pop() || packageName;
|
|
755
|
+
const possiblePaths = [
|
|
756
|
+
`../packages/${packageNameParts}/package.json`,
|
|
757
|
+
`../packages/${packageBaseName}/package.json`,
|
|
758
|
+
`../${packageNameParts}/package.json`,
|
|
759
|
+
`../${packageBaseName}/package.json`,
|
|
760
|
+
`./packages/${packageNameParts}/package.json`,
|
|
761
|
+
`./packages/${packageBaseName}/package.json`,
|
|
762
|
+
`./${packageNameParts}/package.json`,
|
|
763
|
+
`./${packageBaseName}/package.json`
|
|
764
|
+
];
|
|
765
|
+
for (const pkgPath of possiblePaths) {
|
|
766
|
+
try {
|
|
767
|
+
const resolvedPath = Path3.resolve(cwd, pkgPath);
|
|
768
|
+
if (await fileExists(resolvedPath)) {
|
|
769
|
+
const pkgContent = await FS3.readFile(resolvedPath, "utf-8");
|
|
770
|
+
const pkgJson = JSON.parse(pkgContent);
|
|
771
|
+
if (pkgJson.name === packageName) {
|
|
772
|
+
console.info(` Resolved workspace:* dependency "${packageName}" to ^${pkgJson.version}`);
|
|
773
|
+
return `^${pkgJson.version}`;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
} catch {
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
console.warn(`\u26A0\uFE0F WARNING: Could not resolve workspace dependency "${packageName}" - keeping as workspace:*`);
|
|
781
|
+
console.warn(` Searched in: ${possiblePaths.map((p) => Path3.resolve(cwd, p)).join(", ")}`);
|
|
782
|
+
return workspaceSpec;
|
|
783
|
+
}
|
|
784
|
+
const versionPart = workspaceSpec.replace("workspace:", "");
|
|
785
|
+
if (versionPart !== "*") {
|
|
786
|
+
console.info(` Resolved workspace:${versionPart} dependency "${packageName}" to ${versionPart}`);
|
|
787
|
+
return versionPart;
|
|
788
|
+
}
|
|
789
|
+
return workspaceSpec;
|
|
790
|
+
} catch (error) {
|
|
791
|
+
console.warn(`\u26A0\uFE0F WARNING: Error resolving workspace dependency "${packageName}": ${error.message}`);
|
|
792
|
+
return workspaceSpec;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
async function cleanPackageJSON(pkg, mainEntry, options, cwd, distDir) {
|
|
564
796
|
const cleaned = {
|
|
565
797
|
name: pkg.name,
|
|
566
798
|
version: pkg.version
|
|
@@ -611,6 +843,8 @@ function cleanPackageJSON(pkg, mainEntry, options) {
|
|
|
611
843
|
cleaned[field] = transformBinPaths(pkg[field]);
|
|
612
844
|
} else if (pathFields.includes(field)) {
|
|
613
845
|
cleaned[field] = transformSrcToDist(pkg[field]);
|
|
846
|
+
} else if (field === "dependencies" || field === "devDependencies" || field === "peerDependencies" || field === "optionalDependencies") {
|
|
847
|
+
cleaned[field] = await resolveWorkspaceDependencies(pkg[field], cwd);
|
|
614
848
|
} else {
|
|
615
849
|
cleaned[field] = pkg[field];
|
|
616
850
|
}
|
|
@@ -623,7 +857,13 @@ function cleanPackageJSON(pkg, mainEntry, options) {
|
|
|
623
857
|
cleaned.main = `src/${mainEntry}.cjs`;
|
|
624
858
|
}
|
|
625
859
|
cleaned.module = `src/${mainEntry}.js`;
|
|
626
|
-
|
|
860
|
+
if (distDir) {
|
|
861
|
+
const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
|
|
862
|
+
const exists = await fileExists(dtsPath);
|
|
863
|
+
if (exists) {
|
|
864
|
+
cleaned.types = `src/${mainEntry}.d.ts`;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
627
867
|
return cleaned;
|
|
628
868
|
}
|
|
629
869
|
async function fileExists(filePath) {
|
|
@@ -660,7 +900,7 @@ async function build2(cwd, save = false) {
|
|
|
660
900
|
const pkgPath = Path3.join(cwd, "package.json");
|
|
661
901
|
const pkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
|
|
662
902
|
if (pkg.bin) {
|
|
663
|
-
await validateBinPaths(pkg.bin,
|
|
903
|
+
await validateBinPaths(pkg.bin, cwd, save, "bin");
|
|
664
904
|
}
|
|
665
905
|
if (!pkg.private) {
|
|
666
906
|
console.warn("\u26A0\uFE0F WARNING: Root package.json is not private - this could lead to accidental publishing of development package.json");
|
|
@@ -675,9 +915,19 @@ async function build2(cwd, save = false) {
|
|
|
675
915
|
console.warn(" Add 'dist/' to your .gitignore file");
|
|
676
916
|
}
|
|
677
917
|
}
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
918
|
+
const binDir = Path3.join(cwd, "bin");
|
|
919
|
+
const srcEntries = await findEntrypoints(srcDir);
|
|
920
|
+
const binEntries = await findBinEntrypoints(binDir);
|
|
921
|
+
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
922
|
+
const entries = [
|
|
923
|
+
...srcEntries,
|
|
924
|
+
...allBinEntries.map((entry) => `bin/${entry.name}`)
|
|
925
|
+
];
|
|
926
|
+
if (srcEntries.length === 0 && allBinEntries.length === 0) {
|
|
927
|
+
throw new Error("No entry points found in src/ or bin/");
|
|
928
|
+
}
|
|
929
|
+
if (allBinEntries.length > 0) {
|
|
930
|
+
console.info(` Found bin entries: ${allBinEntries.map((entry) => entry.name).join(", ")}`);
|
|
681
931
|
}
|
|
682
932
|
const options = {
|
|
683
933
|
formats: {
|
|
@@ -688,7 +938,7 @@ async function build2(cwd, save = false) {
|
|
|
688
938
|
umd: entries.includes("umd")
|
|
689
939
|
}
|
|
690
940
|
};
|
|
691
|
-
const mainEntry = detectMainEntry(pkg,
|
|
941
|
+
const mainEntry = detectMainEntry(pkg, srcEntries);
|
|
692
942
|
console.info(" Found entries:", entries.join(", "));
|
|
693
943
|
console.info(" Main entry:", mainEntry);
|
|
694
944
|
if (options.formats.cjs) {
|
|
@@ -719,11 +969,29 @@ async function build2(cwd, save = false) {
|
|
|
719
969
|
const entryPoints = [];
|
|
720
970
|
const umdEntries = [];
|
|
721
971
|
for (const entry of entries) {
|
|
722
|
-
|
|
723
|
-
|
|
972
|
+
let entryPath;
|
|
973
|
+
let jsEntryPath;
|
|
974
|
+
let sourceDir;
|
|
975
|
+
if (entry.startsWith("bin/")) {
|
|
976
|
+
const binEntryName = entry.replace("bin/", "");
|
|
977
|
+
const binEntryInfo = allBinEntries.find((binEntry) => binEntry.name === binEntryName);
|
|
978
|
+
if (binEntryInfo?.source === "src") {
|
|
979
|
+
entryPath = Path3.join(srcDir, "bin", `${binEntryName}.ts`);
|
|
980
|
+
jsEntryPath = Path3.join(srcDir, "bin", `${binEntryName}.js`);
|
|
981
|
+
sourceDir = "src/bin/";
|
|
982
|
+
} else {
|
|
983
|
+
entryPath = Path3.join(binDir, `${binEntryName}.ts`);
|
|
984
|
+
jsEntryPath = Path3.join(binDir, `${binEntryName}.js`);
|
|
985
|
+
sourceDir = "bin/";
|
|
986
|
+
}
|
|
987
|
+
} else {
|
|
988
|
+
entryPath = Path3.join(srcDir, `${entry}.ts`);
|
|
989
|
+
jsEntryPath = Path3.join(srcDir, `${entry}.js`);
|
|
990
|
+
sourceDir = "src/";
|
|
991
|
+
}
|
|
724
992
|
const actualPath = await fileExists(entryPath) ? entryPath : jsEntryPath;
|
|
725
993
|
if (!await fileExists(actualPath)) {
|
|
726
|
-
throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry}.ts or ${entry}.js in
|
|
994
|
+
throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry.replace("bin/", "")}.ts or ${entry.replace("bin/", "")}.js in ${sourceDir} directory.`);
|
|
727
995
|
}
|
|
728
996
|
if (entry === "umd") {
|
|
729
997
|
umdEntries.push(actualPath);
|
|
@@ -731,58 +999,107 @@ async function build2(cwd, save = false) {
|
|
|
731
999
|
entryPoints.push(actualPath);
|
|
732
1000
|
}
|
|
733
1001
|
}
|
|
1002
|
+
const srcEntryPoints = entryPoints.filter((path) => path.includes(srcDir));
|
|
1003
|
+
const binEntryPoints = entryPoints.filter((path) => path.includes(binDir));
|
|
1004
|
+
const distBinDir = Path3.join(distDir, "bin");
|
|
1005
|
+
if (binEntryPoints.length > 0) {
|
|
1006
|
+
await FS3.mkdir(distBinDir, { recursive: true });
|
|
1007
|
+
}
|
|
734
1008
|
if (entryPoints.length > 0) {
|
|
735
|
-
|
|
1009
|
+
console.info(` Building ${entryPoints.length} entries (ESM)...`);
|
|
1010
|
+
const srcEntryNames = srcEntryPoints.map((path) => {
|
|
736
1011
|
const name = Path3.basename(path, Path3.extname(path));
|
|
737
1012
|
return name;
|
|
738
1013
|
});
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
outdir: distSrcDir,
|
|
743
|
-
format: "esm",
|
|
744
|
-
outExtension: { ".js": ".js" },
|
|
745
|
-
bundle: true,
|
|
746
|
-
minify: false,
|
|
747
|
-
sourcemap: false,
|
|
748
|
-
external: externalDeps,
|
|
749
|
-
platform: "node",
|
|
750
|
-
target: "node18",
|
|
751
|
-
packages: "external",
|
|
752
|
-
supported: { "import-attributes": true },
|
|
753
|
-
plugins: [
|
|
754
|
-
externalEntrypointsPlugin({
|
|
755
|
-
entryNames,
|
|
756
|
-
outputExtension: ".js"
|
|
757
|
-
}),
|
|
758
|
-
dtsPlugin({
|
|
759
|
-
outDir: distSrcDir,
|
|
760
|
-
rootDir: srcDir,
|
|
761
|
-
entryPoints
|
|
762
|
-
})
|
|
763
|
-
]
|
|
1014
|
+
const binEntryNames = binEntryPoints.map((path) => {
|
|
1015
|
+
const name = Path3.basename(path, Path3.extname(path));
|
|
1016
|
+
return name;
|
|
764
1017
|
});
|
|
765
|
-
|
|
766
|
-
|
|
1018
|
+
const allESMEntryPoints = [...srcEntryPoints, ...binEntryPoints];
|
|
1019
|
+
const allEntryNames = [...srcEntryNames, ...binEntryNames];
|
|
1020
|
+
if (allESMEntryPoints.length > 0) {
|
|
767
1021
|
await ESBuild.build({
|
|
768
|
-
entryPoints,
|
|
769
|
-
outdir:
|
|
770
|
-
|
|
771
|
-
|
|
1022
|
+
entryPoints: allESMEntryPoints,
|
|
1023
|
+
outdir: distDir,
|
|
1024
|
+
outbase: cwd,
|
|
1025
|
+
// Preserve src/ and bin/ directory structure
|
|
1026
|
+
format: "esm",
|
|
1027
|
+
outExtension: { ".js": ".js" },
|
|
772
1028
|
bundle: true,
|
|
773
1029
|
minify: false,
|
|
774
1030
|
sourcemap: false,
|
|
775
1031
|
external: externalDeps,
|
|
776
1032
|
platform: "node",
|
|
777
1033
|
target: "node18",
|
|
1034
|
+
packages: "external",
|
|
778
1035
|
supported: { "import-attributes": true },
|
|
779
1036
|
plugins: [
|
|
780
1037
|
externalEntrypointsPlugin({
|
|
781
|
-
entryNames,
|
|
782
|
-
outputExtension: ".
|
|
783
|
-
})
|
|
1038
|
+
entryNames: allEntryNames,
|
|
1039
|
+
outputExtension: ".js"
|
|
1040
|
+
}),
|
|
1041
|
+
// Generate TypeScript declarations for src entries
|
|
1042
|
+
...srcEntryPoints.length > 0 ? [dtsPlugin({
|
|
1043
|
+
outDir: distSrcDir,
|
|
1044
|
+
rootDir: srcDir,
|
|
1045
|
+
entryPoints: srcEntryPoints
|
|
1046
|
+
})] : [],
|
|
1047
|
+
// Generate TypeScript declarations for bin entries
|
|
1048
|
+
...binEntryPoints.length > 0 ? [dtsPlugin({
|
|
1049
|
+
outDir: distBinDir,
|
|
1050
|
+
rootDir: binDir,
|
|
1051
|
+
entryPoints: binEntryPoints
|
|
1052
|
+
})] : []
|
|
784
1053
|
]
|
|
785
1054
|
});
|
|
1055
|
+
if (binEntryPoints.length > 0) {
|
|
1056
|
+
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
1057
|
+
for (const binEntryName of binEntryNames) {
|
|
1058
|
+
const outputPath = Path3.join(distBinDir, `${binEntryName}.js`);
|
|
1059
|
+
await processJavaScriptExecutable(outputPath, runtimeBanner);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (options.formats.cjs) {
|
|
1064
|
+
console.info(` Building ${entryPoints.length} entries (CJS)...`);
|
|
1065
|
+
if (srcEntryPoints.length > 0) {
|
|
1066
|
+
try {
|
|
1067
|
+
await ESBuild.build({
|
|
1068
|
+
entryPoints: srcEntryPoints,
|
|
1069
|
+
outdir: distSrcDir,
|
|
1070
|
+
format: "cjs",
|
|
1071
|
+
outExtension: { ".js": ".cjs" },
|
|
1072
|
+
bundle: true,
|
|
1073
|
+
minify: false,
|
|
1074
|
+
sourcemap: false,
|
|
1075
|
+
external: externalDeps,
|
|
1076
|
+
platform: "node",
|
|
1077
|
+
target: "node18",
|
|
1078
|
+
supported: { "import-attributes": true },
|
|
1079
|
+
plugins: [
|
|
1080
|
+
externalEntrypointsPlugin({
|
|
1081
|
+
entryNames: srcEntryNames,
|
|
1082
|
+
outputExtension: ".cjs"
|
|
1083
|
+
})
|
|
1084
|
+
]
|
|
1085
|
+
});
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
const errorMessage = error.message || "";
|
|
1088
|
+
const hasErrorsArray = error.errors && Array.isArray(error.errors);
|
|
1089
|
+
const isTLAError = errorMessage.includes('Top-level await is currently not supported with the "cjs" output format') || hasErrorsArray && error.errors.some((e) => e.text && e.text.includes('Top-level await is currently not supported with the "cjs" output format'));
|
|
1090
|
+
if (isTLAError) {
|
|
1091
|
+
console.info(`
|
|
1092
|
+
\u26A0\uFE0F Top-level await detected - CommonJS generation disabled`);
|
|
1093
|
+
console.info(` Top-level await is incompatible with CommonJS format`);
|
|
1094
|
+
console.info(` Building ESM-only (Node.js 14+ and modern bundlers supported)`);
|
|
1095
|
+
console.info(` To permanently disable CJS: remove "main" field from package.json
|
|
1096
|
+
`);
|
|
1097
|
+
options.formats.cjs = false;
|
|
1098
|
+
} else {
|
|
1099
|
+
throw error;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
786
1103
|
}
|
|
787
1104
|
}
|
|
788
1105
|
for (const umdPath of umdEntries) {
|
|
@@ -805,8 +1122,8 @@ async function build2(cwd, save = false) {
|
|
|
805
1122
|
}
|
|
806
1123
|
const autoDiscoveredFiles = [];
|
|
807
1124
|
console.info(" Generating package.json...");
|
|
808
|
-
const cleanedPkg = cleanPackageJSON(pkg, mainEntry, options);
|
|
809
|
-
const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
|
|
1125
|
+
const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd, distDir);
|
|
1126
|
+
const exportsResult = await generateExports(entries, mainEntry, options, pkg.exports, distDir, allBinEntries);
|
|
810
1127
|
cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
|
|
811
1128
|
if (exportsResult.staleExports.length > 0) {
|
|
812
1129
|
console.warn(`\u26A0\uFE0F WARNING: Found ${exportsResult.staleExports.length} stale export(s) pointing to missing src/ files:`);
|
|
@@ -907,7 +1224,10 @@ async function build2(cwd, save = false) {
|
|
|
907
1224
|
rootPkg2.main = `./dist/src/${mainEntry}.cjs`;
|
|
908
1225
|
}
|
|
909
1226
|
rootPkg2.module = `./dist/src/${mainEntry}.js`;
|
|
910
|
-
|
|
1227
|
+
const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
|
|
1228
|
+
if (await fileExists(dtsPath)) {
|
|
1229
|
+
rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
|
|
1230
|
+
}
|
|
911
1231
|
if (rootPkg2.typings && typeof rootPkg2.typings === "string") {
|
|
912
1232
|
rootPkg2.typings = rootPkg2.typings.startsWith("./dist/") ? rootPkg2.typings : "./" + Path3.join("dist", rootPkg2.typings);
|
|
913
1233
|
}
|
|
@@ -938,6 +1258,27 @@ async function build2(cwd, save = false) {
|
|
|
938
1258
|
}
|
|
939
1259
|
}
|
|
940
1260
|
rootPkg2.exports = rootExports;
|
|
1261
|
+
if (allBinEntries.length > 0) {
|
|
1262
|
+
const generatedBin = {};
|
|
1263
|
+
for (const binEntryInfo of allBinEntries) {
|
|
1264
|
+
const binPath = binEntryInfo.source === "src" ? `./dist/src/bin/${binEntryInfo.name}.js` : `./dist/bin/${binEntryInfo.name}.js`;
|
|
1265
|
+
const fullPath = Path3.join(cwd, binPath);
|
|
1266
|
+
if (await fileExists(fullPath)) {
|
|
1267
|
+
generatedBin[binEntryInfo.name] = binPath;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (Object.keys(generatedBin).length > 0) {
|
|
1271
|
+
if (rootPkg2.bin) {
|
|
1272
|
+
if (typeof rootPkg2.bin === "string") {
|
|
1273
|
+
const existingName = pkg.name?.split("/").pop() || "cli";
|
|
1274
|
+
rootPkg2.bin = { [existingName]: rootPkg2.bin };
|
|
1275
|
+
}
|
|
1276
|
+
rootPkg2.bin = { ...rootPkg2.bin, ...generatedBin };
|
|
1277
|
+
} else {
|
|
1278
|
+
rootPkg2.bin = generatedBin;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
941
1282
|
if (rootPkg2.bin) {
|
|
942
1283
|
if (typeof rootPkg2.bin === "string") {
|
|
943
1284
|
const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
|
|
@@ -1000,6 +1341,9 @@ async function build2(cwd, save = false) {
|
|
|
1000
1341
|
if (save) {
|
|
1001
1342
|
rootPkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
|
|
1002
1343
|
}
|
|
1344
|
+
if (allBinEntries.length > 0 || pkg.bin) {
|
|
1345
|
+
await makeFilesExecutable(pkg, cwd, allBinEntries);
|
|
1346
|
+
}
|
|
1003
1347
|
return { distPkg: fixedDistPkg, rootPkg };
|
|
1004
1348
|
}
|
|
1005
1349
|
async function publish(cwd, save = true, extraArgs = []) {
|