@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/src/libuild.cjs CHANGED
@@ -215088,6 +215088,21 @@ function externalEntrypointsPlugin(options) {
215088
215088
  };
215089
215089
  }
215090
215090
  });
215091
+ build3.onResolve({ filter: /^\.\.\/(?:src|bin)\// }, (args) => {
215092
+ const withoutExt = args.path.replace(/\.(ts|js)$/, "");
215093
+ const match = withoutExt.match(/^\.\.\/(?:src|bin)\/(.+)$/);
215094
+ if (match) {
215095
+ const entryName = match[1];
215096
+ if (externalEntries.includes(entryName)) {
215097
+ const dir = withoutExt.match(/^(\.\.\/(?:src|bin))\//)?.[1];
215098
+ return {
215099
+ path: `${dir}/${entryName}${outputExtension}`,
215100
+ external: true
215101
+ };
215102
+ }
215103
+ }
215104
+ return void 0;
215105
+ });
215091
215106
  }
215092
215107
  };
215093
215108
  }
@@ -215113,27 +215128,34 @@ function dtsPlugin(options) {
215113
215128
  let TS;
215114
215129
  try {
215115
215130
  TS = await Promise.resolve().then(() => __toESM(require_typescript(), 1));
215116
- } catch {
215131
+ } catch (error) {
215117
215132
  return;
215118
215133
  }
215119
215134
  const tsFiles = entryFiles.filter((file) => {
215120
215135
  if (!file.endsWith(".ts"))
215121
215136
  return false;
215122
215137
  return options.entryPoints.some((entryPoint) => {
215123
- const normalizedEntry = Path2.resolve(entryPoint);
215124
- const normalizedFile = Path2.resolve(file);
215125
- return normalizedEntry === normalizedFile;
215138
+ try {
215139
+ const fs = require("fs");
215140
+ const normalizedEntry = fs.realpathSync(Path2.resolve(entryPoint));
215141
+ const normalizedFile = fs.realpathSync(Path2.resolve(file));
215142
+ return normalizedEntry === normalizedFile;
215143
+ } catch {
215144
+ const normalizedEntry = Path2.resolve(entryPoint);
215145
+ const normalizedFile = Path2.resolve(file);
215146
+ return normalizedEntry === normalizedFile;
215147
+ }
215126
215148
  });
215127
215149
  });
215128
215150
  if (tsFiles.length === 0) {
215129
215151
  return;
215130
215152
  }
215131
215153
  try {
215154
+ await FS2.mkdir(options.outDir, { recursive: true });
215132
215155
  const compilerOptions = {
215133
215156
  declaration: true,
215134
215157
  emitDeclarationOnly: true,
215135
215158
  outDir: options.outDir,
215136
- rootDir: options.rootDir,
215137
215159
  skipLibCheck: true,
215138
215160
  esModuleInterop: true,
215139
215161
  target: TS.ScriptTarget.ES2020,
@@ -215208,6 +215230,38 @@ ${content}`;
215208
215230
  }
215209
215231
 
215210
215232
  // src/libuild.ts
215233
+ function generateRuntimeBanner(pkg) {
215234
+ const prefersBun = pkg.engines?.bun !== void 0;
215235
+ if (prefersBun) {
215236
+ return '//bin/true; exec "$({ [ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] || true; } && command -v bun || command -v node)" "$0" "$@"';
215237
+ } else {
215238
+ return '//bin/true; exec "$([ "${npm_config_user_agent#bun/}" != "$npm_config_user_agent" ] && command -v bun || command -v node)" "$0" "$@"';
215239
+ }
215240
+ }
215241
+ async function processJavaScriptExecutable(filePath, runtimeBanner) {
215242
+ try {
215243
+ const contents = await FS3.readFile(filePath, "utf8");
215244
+ const lines = contents.split("\n");
215245
+ let modified = false;
215246
+ if (lines[0]?.startsWith("#!")) {
215247
+ const existingShebang = lines[0];
215248
+ if (existingShebang.includes("python") || existingShebang.includes("bash") || !existingShebang.includes("node") && !existingShebang.includes("bun") && !existingShebang.includes("sh")) {
215249
+ console.warn(`\u26A0\uFE0F WARNING: ${filePath} has non-JavaScript shebang but is a JS file. Adding dual runtime support.`);
215250
+ }
215251
+ lines[0] = "#!/usr/bin/env sh";
215252
+ lines.splice(1, 0, runtimeBanner);
215253
+ modified = true;
215254
+ } else {
215255
+ lines.unshift("#!/usr/bin/env sh", runtimeBanner);
215256
+ modified = true;
215257
+ }
215258
+ if (modified) {
215259
+ await FS3.writeFile(filePath, lines.join("\n"));
215260
+ }
215261
+ } catch (error) {
215262
+ console.warn(`\u26A0\uFE0F WARNING: Could not process executable ${filePath}: ${error.message}`);
215263
+ }
215264
+ }
215211
215265
  function isValidEntrypoint(filename) {
215212
215266
  if (!filename.endsWith(".ts") && !filename.endsWith(".js"))
215213
215267
  return false;
@@ -215234,6 +215288,22 @@ async function findEntrypoints(srcDir) {
215234
215288
  return isValidEntrypoint(dirent.name);
215235
215289
  }).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
215236
215290
  }
215291
+ async function findBinEntrypoints(binDir) {
215292
+ try {
215293
+ const files = await FS3.readdir(binDir, { withFileTypes: true });
215294
+ return files.filter((dirent) => {
215295
+ if (dirent.isDirectory()) {
215296
+ return false;
215297
+ }
215298
+ return isValidEntrypoint(dirent.name);
215299
+ }).map((dirent) => Path3.basename(dirent.name, Path3.extname(dirent.name))).sort();
215300
+ } catch (error) {
215301
+ if (error.code === "ENOENT") {
215302
+ return [];
215303
+ }
215304
+ throw error;
215305
+ }
215306
+ }
215237
215307
  function detectMainEntry(pkg, entries) {
215238
215308
  function extractEntryFromPath(path) {
215239
215309
  const match = path.match(/\.\/src\/([^.]+)/);
@@ -215331,18 +215401,38 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
215331
215401
  }
215332
215402
  return entryName ? !entries.includes(entryName) : false;
215333
215403
  }
215334
- function generateExports(entries, mainEntry, options, existingExports = {}) {
215404
+ async function generateExports(entries, mainEntry, options, existingExports = {}, distDir, allBinEntries = []) {
215335
215405
  const exports2 = {};
215336
215406
  const staleExports = [];
215337
- function createExportEntry(entry) {
215338
- const exportEntry = {
215339
- types: `./src/${entry}.d.ts`,
215340
- import: `./src/${entry}.js`
215341
- };
215342
- if (options.formats.cjs) {
215343
- exportEntry.require = `./src/${entry}.cjs`;
215407
+ async function createExportEntry(entry) {
215408
+ if (entry.startsWith("bin/")) {
215409
+ const binEntry = entry.replace("bin/", "");
215410
+ const exportEntry = {
215411
+ import: `./bin/${binEntry}.js`
215412
+ };
215413
+ if (distDir) {
215414
+ const dtsPath = Path3.join(distDir, "bin", `${binEntry}.d.ts`);
215415
+ if (await fileExists(dtsPath)) {
215416
+ exportEntry.types = `./bin/${binEntry}.d.ts`;
215417
+ }
215418
+ }
215419
+ return exportEntry;
215420
+ } else {
215421
+ const exportEntry = {
215422
+ import: `./src/${entry}.js`
215423
+ };
215424
+ if (distDir) {
215425
+ const dtsPath = Path3.join(distDir, "src", `${entry}.d.ts`);
215426
+ const exists = await fileExists(dtsPath);
215427
+ if (exists) {
215428
+ exportEntry.types = `./src/${entry}.d.ts`;
215429
+ }
215430
+ }
215431
+ if (options.formats.cjs) {
215432
+ exportEntry.require = `./src/${entry}.cjs`;
215433
+ }
215434
+ return exportEntry;
215344
215435
  }
215345
- return exportEntry;
215346
215436
  }
215347
215437
  function expandExistingExport(existing, entryFromPath) {
215348
215438
  if (typeof existing === "string") {
@@ -215416,7 +215506,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
215416
215506
  }
215417
215507
  }
215418
215508
  if (!exports2["."]) {
215419
- exports2["."] = createExportEntry(mainEntry);
215509
+ exports2["."] = await createExportEntry(mainEntry);
215420
215510
  } else {
215421
215511
  exports2["."] = expandExistingExport(exports2["."], mainEntry);
215422
215512
  }
@@ -215425,7 +215515,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
215425
215515
  continue;
215426
215516
  const key = `./${entry}`;
215427
215517
  if (!exports2[key]) {
215428
- exports2[key] = createExportEntry(entry);
215518
+ exports2[key] = await createExportEntry(entry);
215429
215519
  } else {
215430
215520
  exports2[key] = expandExistingExport(exports2[key], entry);
215431
215521
  }
@@ -215463,67 +215553,96 @@ function transformSrcToDist(value) {
215463
215553
  }
215464
215554
  return value;
215465
215555
  }
215466
- async function validateBinPaths(value, srcDir, fieldName = "bin") {
215556
+ async function validateBinPaths(value, cwd, save, fieldName = "bin") {
215467
215557
  if (typeof value === "string") {
215468
- await validateSingleBinPath(value, fieldName, srcDir);
215558
+ await validateSingleBinPath(value, fieldName, cwd, save);
215469
215559
  } else if (typeof value === "object" && value !== null) {
215470
215560
  for (const [key, val] of Object.entries(value)) {
215471
215561
  if (typeof val === "string") {
215472
- await validateSingleBinPath(val, `${fieldName}.${key}`, srcDir);
215562
+ await validateSingleBinPath(val, `${fieldName}.${key}`, cwd, save);
215473
215563
  }
215474
215564
  }
215475
215565
  }
215476
215566
  }
215477
- async function validateSingleBinPath(binPath, fieldName, srcDir) {
215478
- if (binPath.startsWith("dist/") || binPath.startsWith("./dist/")) {
215567
+ async function validateSingleBinPath(binPath, fieldName, cwd, save) {
215568
+ if (save) {
215569
+ return;
215570
+ }
215571
+ if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/") || binPath.startsWith("dist/bin/") || binPath.startsWith("./dist/bin/")) {
215572
+ const fullPath2 = Path3.join(cwd, binPath);
215573
+ const distExists = await fileExists(fullPath2);
215574
+ if (distExists) {
215575
+ return;
215576
+ }
215479
215577
  let srcPath;
215578
+ let sourceDir;
215480
215579
  if (binPath.startsWith("./dist/src/")) {
215481
215580
  srcPath = binPath.replace("./dist/src/", "src/");
215581
+ sourceDir = "src";
215482
215582
  } else if (binPath.startsWith("dist/src/")) {
215483
215583
  srcPath = binPath.replace("dist/src/", "src/");
215484
- } else if (binPath.startsWith("./dist/")) {
215485
- srcPath = binPath.replace("./dist/", "src/");
215486
- } else if (binPath.startsWith("dist/")) {
215487
- srcPath = binPath.replace("dist/", "src/");
215584
+ sourceDir = "src";
215585
+ } else if (binPath.startsWith("./dist/bin/")) {
215586
+ srcPath = binPath.replace("./dist/bin/", "bin/");
215587
+ sourceDir = "bin";
215588
+ } else if (binPath.startsWith("dist/bin/")) {
215589
+ srcPath = binPath.replace("dist/bin/", "bin/");
215590
+ sourceDir = "bin";
215488
215591
  } else {
215489
- srcPath = "";
215592
+ srcPath = binPath;
215593
+ sourceDir = "src";
215490
215594
  }
215491
- const basePath = srcPath.replace(/\.(js|cjs)$/, "");
215492
- const tsPath = Path3.join(srcDir, "..", basePath + ".ts");
215493
- const jsPath = Path3.join(srcDir, "..", basePath + ".js");
215595
+ const basePath = srcPath.replace(/\.(js|cjs|mjs)$/, "");
215596
+ const tsPath = Path3.join(cwd, basePath + ".ts");
215597
+ const jsPath = Path3.join(cwd, basePath + ".js");
215494
215598
  const srcExists = await fileExists(tsPath) || await fileExists(jsPath);
215495
215599
  if (!srcExists) {
215496
- throw new Error(`${fieldName} field points to dist/ directory: "${binPath}"
215497
-
215498
- The bin field should reference source files that libuild will build and transform:
215499
- CORRECT: "bin": {"tool": "src/cli.js"}
215500
- INCORRECT: "bin": {"tool": "dist/cli.js"}
215501
-
215502
- Libuild workflow:
215503
- 1. Point bin entries to src/ files
215504
- 2. Run 'libuild build --save' to update package.json with dist/ paths
215505
- 3. Set "private": true in your development package.json
215506
-
215507
- If you need to include pre-built executable files, use the files field instead:
215508
- "files": ["scripts/my-tool.js"]`);
215600
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" but neither the dist file nor corresponding src file exists.
215601
+
215602
+ Create "${srcPath}" and run 'libuild build --save' to update paths correctly.`);
215603
+ return;
215509
215604
  }
215510
- console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to dist/ directory: "${binPath}"
215605
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist yet.
215511
215606
 
215512
- libuild is ZERO-CONFIG - there is no libuild.config.js file!
215513
- Configuration comes from your package.json fields.
215607
+ Run 'libuild build' to create the dist files, or use 'libuild build --save' to update the path to "${srcPath}".`);
215608
+ return;
215609
+ }
215610
+ if (binPath.startsWith("dist/") || binPath.startsWith("./dist/")) {
215611
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" in dist/ directory.
215514
215612
 
215515
- The libuild workflow is to point bin entries to src/ files and use --save to update paths.
215516
- Consider changing to: "${srcPath}" and running 'libuild build --save'`);
215613
+ libuild expects bin entries to point to src/ files. Consider changing to the corresponding src/ path and using --save.`);
215517
215614
  return;
215518
215615
  }
215519
- if (binPath.startsWith("src/") || binPath.startsWith("./src/")) {
215616
+ const fullPath = Path3.join(cwd, binPath);
215617
+ const pathExists = await fileExists(fullPath);
215618
+ if (pathExists) {
215520
215619
  return;
215521
215620
  }
215522
- if (!binPath.startsWith("src/") && !binPath.startsWith("./src/")) {
215523
- console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which is not in src/ directory.
215524
- Consider moving executable to src/ or using the files field for pre-built scripts.
215525
- Run 'libuild build --save' after fixing to update paths correctly.`);
215621
+ if (binPath.startsWith("src/") || binPath.startsWith("./src/") || binPath.startsWith("bin/") || binPath.startsWith("./bin/")) {
215622
+ let normalizedPath = binPath.startsWith("./") ? binPath.slice(2) : binPath;
215623
+ if (normalizedPath.startsWith("src/")) {
215624
+ const srcRelativePath = normalizedPath.replace("src/", "");
215625
+ if (srcRelativePath.includes("/")) {
215626
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which is in a subdirectory of src/.`);
215627
+ console.warn(` libuild only auto-detects top-level src/ files as entrypoints.`);
215628
+ console.warn(` Consider moving the file to the top-level src/ directory or use the bin/ directory for executables.`);
215629
+ }
215630
+ }
215631
+ const basePath = fullPath.replace(/\.(js|cjs|mjs)$/, "");
215632
+ const tsPath = basePath + ".ts";
215633
+ const jsPath = basePath + ".js";
215634
+ const tsExists = await fileExists(tsPath);
215635
+ const jsExists = await fileExists(jsPath);
215636
+ if (tsExists || jsExists) {
215637
+ return;
215638
+ }
215526
215639
  }
215640
+ console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist
215641
+
215642
+ libuild is ZERO-CONFIG - there is no libuild.config.js file!
215643
+ Configuration comes from your package.json fields.
215644
+
215645
+ Use 'libuild build --save' to update package.json with correct dist/ paths automatically.`);
215527
215646
  }
215528
215647
  function transformBinPaths(value) {
215529
215648
  if (typeof value === "string") {
@@ -215533,10 +215652,19 @@ function transformBinPaths(value) {
215533
215652
  if (value.startsWith("dist/src/")) {
215534
215653
  return value.replace("dist/", "");
215535
215654
  }
215655
+ if (value.startsWith("./dist/bin/")) {
215656
+ return value.replace("./dist/", "");
215657
+ }
215658
+ if (value.startsWith("dist/bin/")) {
215659
+ return value.replace("dist/", "");
215660
+ }
215536
215661
  if (value.startsWith("./src/")) {
215537
215662
  return value.replace("./", "");
215538
215663
  }
215539
- if (value.startsWith("src/") || value === "src") {
215664
+ if (value.startsWith("./bin/")) {
215665
+ return value.replace("./", "");
215666
+ }
215667
+ if (value.startsWith("src/") || value === "src" || value.startsWith("bin/") || value === "bin") {
215540
215668
  return value;
215541
215669
  }
215542
215670
  return value;
@@ -215581,7 +215709,103 @@ function fixExportsForDist(obj) {
215581
215709
  }
215582
215710
  return obj;
215583
215711
  }
215584
- function cleanPackageJSON(pkg, mainEntry, options) {
215712
+ async function setExecutablePermissions(filePath) {
215713
+ try {
215714
+ await FS3.chmod(filePath, 493);
215715
+ } catch (error) {
215716
+ console.warn(`\u26A0\uFE0F WARNING: Could not set executable permissions for ${filePath}: ${error.message}`);
215717
+ }
215718
+ }
215719
+ async function makeFilesExecutable(pkg, cwd, allBinEntries) {
215720
+ const filesToMakeExecutable = [];
215721
+ if (pkg.bin) {
215722
+ if (typeof pkg.bin === "string") {
215723
+ filesToMakeExecutable.push(Path3.join(cwd, pkg.bin));
215724
+ } else if (typeof pkg.bin === "object") {
215725
+ for (const binPath of Object.values(pkg.bin)) {
215726
+ if (typeof binPath === "string") {
215727
+ filesToMakeExecutable.push(Path3.join(cwd, binPath));
215728
+ }
215729
+ }
215730
+ }
215731
+ }
215732
+ for (const binEntryInfo of allBinEntries) {
215733
+ const baseDir = binEntryInfo.source === "src" ? "dist/src/bin" : "dist/bin";
215734
+ const jsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.js`);
215735
+ const cjsPath = Path3.join(cwd, baseDir, `${binEntryInfo.name}.cjs`);
215736
+ if (!filesToMakeExecutable.includes(jsPath)) {
215737
+ filesToMakeExecutable.push(jsPath);
215738
+ }
215739
+ if (!filesToMakeExecutable.includes(cjsPath)) {
215740
+ filesToMakeExecutable.push(cjsPath);
215741
+ }
215742
+ }
215743
+ for (const filePath of filesToMakeExecutable) {
215744
+ if (await fileExists(filePath)) {
215745
+ await setExecutablePermissions(filePath);
215746
+ }
215747
+ }
215748
+ }
215749
+ async function resolveWorkspaceDependencies(dependencies, cwd) {
215750
+ if (!dependencies)
215751
+ return void 0;
215752
+ const resolved = {};
215753
+ for (const [depName, depVersion] of Object.entries(dependencies)) {
215754
+ if (depVersion.startsWith("workspace:")) {
215755
+ const resolvedVersion = await resolveWorkspaceVersion(depName, depVersion, cwd);
215756
+ resolved[depName] = resolvedVersion;
215757
+ } else {
215758
+ resolved[depName] = depVersion;
215759
+ }
215760
+ }
215761
+ return resolved;
215762
+ }
215763
+ async function resolveWorkspaceVersion(packageName, workspaceSpec, cwd) {
215764
+ try {
215765
+ if (workspaceSpec === "workspace:*") {
215766
+ const packageNameParts = packageName.replace("@", "").replace("/", "-");
215767
+ const packageBaseName = packageName.split("/").pop() || packageName;
215768
+ const possiblePaths = [
215769
+ `../packages/${packageNameParts}/package.json`,
215770
+ `../packages/${packageBaseName}/package.json`,
215771
+ `../${packageNameParts}/package.json`,
215772
+ `../${packageBaseName}/package.json`,
215773
+ `./packages/${packageNameParts}/package.json`,
215774
+ `./packages/${packageBaseName}/package.json`,
215775
+ `./${packageNameParts}/package.json`,
215776
+ `./${packageBaseName}/package.json`
215777
+ ];
215778
+ for (const pkgPath of possiblePaths) {
215779
+ try {
215780
+ const resolvedPath = Path3.resolve(cwd, pkgPath);
215781
+ if (await fileExists(resolvedPath)) {
215782
+ const pkgContent = await FS3.readFile(resolvedPath, "utf-8");
215783
+ const pkgJson = JSON.parse(pkgContent);
215784
+ if (pkgJson.name === packageName) {
215785
+ console.info(` Resolved workspace:* dependency "${packageName}" to ^${pkgJson.version}`);
215786
+ return `^${pkgJson.version}`;
215787
+ }
215788
+ }
215789
+ } catch {
215790
+ continue;
215791
+ }
215792
+ }
215793
+ console.warn(`\u26A0\uFE0F WARNING: Could not resolve workspace dependency "${packageName}" - keeping as workspace:*`);
215794
+ console.warn(` Searched in: ${possiblePaths.map((p) => Path3.resolve(cwd, p)).join(", ")}`);
215795
+ return workspaceSpec;
215796
+ }
215797
+ const versionPart = workspaceSpec.replace("workspace:", "");
215798
+ if (versionPart !== "*") {
215799
+ console.info(` Resolved workspace:${versionPart} dependency "${packageName}" to ${versionPart}`);
215800
+ return versionPart;
215801
+ }
215802
+ return workspaceSpec;
215803
+ } catch (error) {
215804
+ console.warn(`\u26A0\uFE0F WARNING: Error resolving workspace dependency "${packageName}": ${error.message}`);
215805
+ return workspaceSpec;
215806
+ }
215807
+ }
215808
+ async function cleanPackageJSON(pkg, mainEntry, options, cwd, distDir) {
215585
215809
  const cleaned = {
215586
215810
  name: pkg.name,
215587
215811
  version: pkg.version
@@ -215632,6 +215856,8 @@ function cleanPackageJSON(pkg, mainEntry, options) {
215632
215856
  cleaned[field] = transformBinPaths(pkg[field]);
215633
215857
  } else if (pathFields.includes(field)) {
215634
215858
  cleaned[field] = transformSrcToDist(pkg[field]);
215859
+ } else if (field === "dependencies" || field === "devDependencies" || field === "peerDependencies" || field === "optionalDependencies") {
215860
+ cleaned[field] = await resolveWorkspaceDependencies(pkg[field], cwd);
215635
215861
  } else {
215636
215862
  cleaned[field] = pkg[field];
215637
215863
  }
@@ -215644,7 +215870,13 @@ function cleanPackageJSON(pkg, mainEntry, options) {
215644
215870
  cleaned.main = `src/${mainEntry}.cjs`;
215645
215871
  }
215646
215872
  cleaned.module = `src/${mainEntry}.js`;
215647
- cleaned.types = `src/${mainEntry}.d.ts`;
215873
+ if (distDir) {
215874
+ const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
215875
+ const exists = await fileExists(dtsPath);
215876
+ if (exists) {
215877
+ cleaned.types = `src/${mainEntry}.d.ts`;
215878
+ }
215879
+ }
215648
215880
  return cleaned;
215649
215881
  }
215650
215882
  async function fileExists(filePath) {
@@ -215681,7 +215913,7 @@ async function build2(cwd, save = false) {
215681
215913
  const pkgPath = Path3.join(cwd, "package.json");
215682
215914
  const pkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
215683
215915
  if (pkg.bin) {
215684
- await validateBinPaths(pkg.bin, srcDir, "bin");
215916
+ await validateBinPaths(pkg.bin, cwd, save, "bin");
215685
215917
  }
215686
215918
  if (!pkg.private) {
215687
215919
  console.warn("\u26A0\uFE0F WARNING: Root package.json is not private - this could lead to accidental publishing of development package.json");
@@ -215696,9 +215928,19 @@ async function build2(cwd, save = false) {
215696
215928
  console.warn(" Add 'dist/' to your .gitignore file");
215697
215929
  }
215698
215930
  }
215699
- const entries = await findEntrypoints(srcDir);
215700
- if (entries.length === 0) {
215701
- throw new Error("No entry points found in src/");
215931
+ const binDir = Path3.join(cwd, "bin");
215932
+ const srcEntries = await findEntrypoints(srcDir);
215933
+ const binEntries = await findBinEntrypoints(binDir);
215934
+ const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
215935
+ const entries = [
215936
+ ...srcEntries,
215937
+ ...allBinEntries.map((entry) => `bin/${entry.name}`)
215938
+ ];
215939
+ if (srcEntries.length === 0 && allBinEntries.length === 0) {
215940
+ throw new Error("No entry points found in src/ or bin/");
215941
+ }
215942
+ if (allBinEntries.length > 0) {
215943
+ console.info(` Found bin entries: ${allBinEntries.map((entry) => entry.name).join(", ")}`);
215702
215944
  }
215703
215945
  const options = {
215704
215946
  formats: {
@@ -215709,7 +215951,7 @@ async function build2(cwd, save = false) {
215709
215951
  umd: entries.includes("umd")
215710
215952
  }
215711
215953
  };
215712
- const mainEntry = detectMainEntry(pkg, entries);
215954
+ const mainEntry = detectMainEntry(pkg, srcEntries);
215713
215955
  console.info(" Found entries:", entries.join(", "));
215714
215956
  console.info(" Main entry:", mainEntry);
215715
215957
  if (options.formats.cjs) {
@@ -215740,11 +215982,29 @@ async function build2(cwd, save = false) {
215740
215982
  const entryPoints = [];
215741
215983
  const umdEntries = [];
215742
215984
  for (const entry of entries) {
215743
- const entryPath = Path3.join(srcDir, `${entry}.ts`);
215744
- const jsEntryPath = Path3.join(srcDir, `${entry}.js`);
215985
+ let entryPath;
215986
+ let jsEntryPath;
215987
+ let sourceDir;
215988
+ if (entry.startsWith("bin/")) {
215989
+ const binEntryName = entry.replace("bin/", "");
215990
+ const binEntryInfo = allBinEntries.find((binEntry) => binEntry.name === binEntryName);
215991
+ if (binEntryInfo?.source === "src") {
215992
+ entryPath = Path3.join(srcDir, "bin", `${binEntryName}.ts`);
215993
+ jsEntryPath = Path3.join(srcDir, "bin", `${binEntryName}.js`);
215994
+ sourceDir = "src/bin/";
215995
+ } else {
215996
+ entryPath = Path3.join(binDir, `${binEntryName}.ts`);
215997
+ jsEntryPath = Path3.join(binDir, `${binEntryName}.js`);
215998
+ sourceDir = "bin/";
215999
+ }
216000
+ } else {
216001
+ entryPath = Path3.join(srcDir, `${entry}.ts`);
216002
+ jsEntryPath = Path3.join(srcDir, `${entry}.js`);
216003
+ sourceDir = "src/";
216004
+ }
215745
216005
  const actualPath = await fileExists(entryPath) ? entryPath : jsEntryPath;
215746
216006
  if (!await fileExists(actualPath)) {
215747
- throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry}.ts or ${entry}.js in src/ directory.`);
216007
+ throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry.replace("bin/", "")}.ts or ${entry.replace("bin/", "")}.js in ${sourceDir} directory.`);
215748
216008
  }
215749
216009
  if (entry === "umd") {
215750
216010
  umdEntries.push(actualPath);
@@ -215752,58 +216012,107 @@ async function build2(cwd, save = false) {
215752
216012
  entryPoints.push(actualPath);
215753
216013
  }
215754
216014
  }
216015
+ const srcEntryPoints = entryPoints.filter((path) => path.includes(srcDir));
216016
+ const binEntryPoints = entryPoints.filter((path) => path.includes(binDir));
216017
+ const distBinDir = Path3.join(distDir, "bin");
216018
+ if (binEntryPoints.length > 0) {
216019
+ await FS3.mkdir(distBinDir, { recursive: true });
216020
+ }
215755
216021
  if (entryPoints.length > 0) {
215756
- const entryNames = entryPoints.map((path) => {
216022
+ console.info(` Building ${entryPoints.length} entries (ESM)...`);
216023
+ const srcEntryNames = srcEntryPoints.map((path) => {
215757
216024
  const name = Path3.basename(path, Path3.extname(path));
215758
216025
  return name;
215759
216026
  });
215760
- console.info(` Building ${entryPoints.length} entries (ESM)...`);
215761
- await ESBuild.build({
215762
- entryPoints,
215763
- outdir: distSrcDir,
215764
- format: "esm",
215765
- outExtension: { ".js": ".js" },
215766
- bundle: true,
215767
- minify: false,
215768
- sourcemap: false,
215769
- external: externalDeps,
215770
- platform: "node",
215771
- target: "node18",
215772
- packages: "external",
215773
- supported: { "import-attributes": true },
215774
- plugins: [
215775
- externalEntrypointsPlugin({
215776
- entryNames,
215777
- outputExtension: ".js"
215778
- }),
215779
- dtsPlugin({
215780
- outDir: distSrcDir,
215781
- rootDir: srcDir,
215782
- entryPoints
215783
- })
215784
- ]
216027
+ const binEntryNames = binEntryPoints.map((path) => {
216028
+ const name = Path3.basename(path, Path3.extname(path));
216029
+ return name;
215785
216030
  });
215786
- if (options.formats.cjs) {
215787
- console.info(` Building ${entryPoints.length} entries (CJS)...`);
216031
+ const allESMEntryPoints = [...srcEntryPoints, ...binEntryPoints];
216032
+ const allEntryNames = [...srcEntryNames, ...binEntryNames];
216033
+ if (allESMEntryPoints.length > 0) {
215788
216034
  await ESBuild.build({
215789
- entryPoints,
215790
- outdir: distSrcDir,
215791
- format: "cjs",
215792
- outExtension: { ".js": ".cjs" },
216035
+ entryPoints: allESMEntryPoints,
216036
+ outdir: distDir,
216037
+ outbase: cwd,
216038
+ // Preserve src/ and bin/ directory structure
216039
+ format: "esm",
216040
+ outExtension: { ".js": ".js" },
215793
216041
  bundle: true,
215794
216042
  minify: false,
215795
216043
  sourcemap: false,
215796
216044
  external: externalDeps,
215797
216045
  platform: "node",
215798
216046
  target: "node18",
216047
+ packages: "external",
215799
216048
  supported: { "import-attributes": true },
215800
216049
  plugins: [
215801
216050
  externalEntrypointsPlugin({
215802
- entryNames,
215803
- outputExtension: ".cjs"
215804
- })
216051
+ entryNames: allEntryNames,
216052
+ outputExtension: ".js"
216053
+ }),
216054
+ // Generate TypeScript declarations for src entries
216055
+ ...srcEntryPoints.length > 0 ? [dtsPlugin({
216056
+ outDir: distSrcDir,
216057
+ rootDir: srcDir,
216058
+ entryPoints: srcEntryPoints
216059
+ })] : [],
216060
+ // Generate TypeScript declarations for bin entries
216061
+ ...binEntryPoints.length > 0 ? [dtsPlugin({
216062
+ outDir: distBinDir,
216063
+ rootDir: binDir,
216064
+ entryPoints: binEntryPoints
216065
+ })] : []
215805
216066
  ]
215806
216067
  });
216068
+ if (binEntryPoints.length > 0) {
216069
+ const runtimeBanner = generateRuntimeBanner(pkg);
216070
+ for (const binEntryName of binEntryNames) {
216071
+ const outputPath = Path3.join(distBinDir, `${binEntryName}.js`);
216072
+ await processJavaScriptExecutable(outputPath, runtimeBanner);
216073
+ }
216074
+ }
216075
+ }
216076
+ if (options.formats.cjs) {
216077
+ console.info(` Building ${entryPoints.length} entries (CJS)...`);
216078
+ if (srcEntryPoints.length > 0) {
216079
+ try {
216080
+ await ESBuild.build({
216081
+ entryPoints: srcEntryPoints,
216082
+ outdir: distSrcDir,
216083
+ format: "cjs",
216084
+ outExtension: { ".js": ".cjs" },
216085
+ bundle: true,
216086
+ minify: false,
216087
+ sourcemap: false,
216088
+ external: externalDeps,
216089
+ platform: "node",
216090
+ target: "node18",
216091
+ supported: { "import-attributes": true },
216092
+ plugins: [
216093
+ externalEntrypointsPlugin({
216094
+ entryNames: srcEntryNames,
216095
+ outputExtension: ".cjs"
216096
+ })
216097
+ ]
216098
+ });
216099
+ } catch (error) {
216100
+ const errorMessage = error.message || "";
216101
+ const hasErrorsArray = error.errors && Array.isArray(error.errors);
216102
+ 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'));
216103
+ if (isTLAError) {
216104
+ console.info(`
216105
+ \u26A0\uFE0F Top-level await detected - CommonJS generation disabled`);
216106
+ console.info(` Top-level await is incompatible with CommonJS format`);
216107
+ console.info(` Building ESM-only (Node.js 14+ and modern bundlers supported)`);
216108
+ console.info(` To permanently disable CJS: remove "main" field from package.json
216109
+ `);
216110
+ options.formats.cjs = false;
216111
+ } else {
216112
+ throw error;
216113
+ }
216114
+ }
216115
+ }
215807
216116
  }
215808
216117
  }
215809
216118
  for (const umdPath of umdEntries) {
@@ -215826,8 +216135,8 @@ async function build2(cwd, save = false) {
215826
216135
  }
215827
216136
  const autoDiscoveredFiles = [];
215828
216137
  console.info(" Generating package.json...");
215829
- const cleanedPkg = cleanPackageJSON(pkg, mainEntry, options);
215830
- const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
216138
+ const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd, distDir);
216139
+ const exportsResult = await generateExports(entries, mainEntry, options, pkg.exports, distDir, allBinEntries);
215831
216140
  cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
215832
216141
  if (exportsResult.staleExports.length > 0) {
215833
216142
  console.warn(`\u26A0\uFE0F WARNING: Found ${exportsResult.staleExports.length} stale export(s) pointing to missing src/ files:`);
@@ -215928,7 +216237,10 @@ async function build2(cwd, save = false) {
215928
216237
  rootPkg2.main = `./dist/src/${mainEntry}.cjs`;
215929
216238
  }
215930
216239
  rootPkg2.module = `./dist/src/${mainEntry}.js`;
215931
- rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
216240
+ const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
216241
+ if (await fileExists(dtsPath)) {
216242
+ rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
216243
+ }
215932
216244
  if (rootPkg2.typings && typeof rootPkg2.typings === "string") {
215933
216245
  rootPkg2.typings = rootPkg2.typings.startsWith("./dist/") ? rootPkg2.typings : "./" + Path3.join("dist", rootPkg2.typings);
215934
216246
  }
@@ -215959,6 +216271,27 @@ async function build2(cwd, save = false) {
215959
216271
  }
215960
216272
  }
215961
216273
  rootPkg2.exports = rootExports;
216274
+ if (allBinEntries.length > 0) {
216275
+ const generatedBin = {};
216276
+ for (const binEntryInfo of allBinEntries) {
216277
+ const binPath = binEntryInfo.source === "src" ? `./dist/src/bin/${binEntryInfo.name}.js` : `./dist/bin/${binEntryInfo.name}.js`;
216278
+ const fullPath = Path3.join(cwd, binPath);
216279
+ if (await fileExists(fullPath)) {
216280
+ generatedBin[binEntryInfo.name] = binPath;
216281
+ }
216282
+ }
216283
+ if (Object.keys(generatedBin).length > 0) {
216284
+ if (rootPkg2.bin) {
216285
+ if (typeof rootPkg2.bin === "string") {
216286
+ const existingName = pkg.name?.split("/").pop() || "cli";
216287
+ rootPkg2.bin = { [existingName]: rootPkg2.bin };
216288
+ }
216289
+ rootPkg2.bin = { ...rootPkg2.bin, ...generatedBin };
216290
+ } else {
216291
+ rootPkg2.bin = generatedBin;
216292
+ }
216293
+ }
216294
+ }
215962
216295
  if (rootPkg2.bin) {
215963
216296
  if (typeof rootPkg2.bin === "string") {
215964
216297
  const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
@@ -216021,6 +216354,9 @@ async function build2(cwd, save = false) {
216021
216354
  if (save) {
216022
216355
  rootPkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
216023
216356
  }
216357
+ if (allBinEntries.length > 0 || pkg.bin) {
216358
+ await makeFilesExecutable(pkg, cwd, allBinEntries);
216359
+ }
216024
216360
  return { distPkg: fixedDistPkg, rootPkg };
216025
216361
  }
216026
216362
  async function publish(cwd, save = true, extraArgs = []) {