@b9g/libuild 0.1.8 → 0.1.10

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 CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.1.10] - 2025-10-29
6
+
7
+ ### Added
8
+ - Automatic cleanup of invalid bin/exports paths when using --save flag
9
+ - Clear messaging that libuild is zero-config with NO libuild.config.js file
10
+
11
+ ### Fixed
12
+ - --save now validates and removes bin/exports entries pointing to non-existent files
13
+ - Package.json fields are regenerated based on actual built files during --save
14
+ - Validation logic is now context-aware of --save flag to prevent warnings about configuration that libuild itself creates
15
+ - CLI argument parsing to prevent npm flags from being incorrectly treated as directory arguments
16
+
17
+ ## [0.1.9] - 2025-10-29
18
+
19
+ ### Fixed
20
+ - Preserve import attributes (`with { type: "json" }`) in externalized JSON imports to prevent Node.js runtime errors
21
+ - Upgrade Node.js target to 18+ and engines requirement to >=18.20.0 for import attributes support
22
+
5
23
  ## [0.1.8] - 2025-10-29
6
24
 
7
25
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/libuild",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Zero-config library builds",
5
5
  "keywords": [
6
6
  "build",
@@ -37,7 +37,7 @@
37
37
  }
38
38
  },
39
39
  "engines": {
40
- "node": ">=16.0.0",
40
+ "node": ">=18.20.0",
41
41
  "bun": ">=1.0.0"
42
42
  },
43
43
  "type": "module",
package/src/cli.cjs CHANGED
@@ -56,6 +56,12 @@ Options:
56
56
  --save Update root package.json to point to dist files
57
57
  --no-save Skip package.json updates (for publish command)
58
58
 
59
+ IMPORTANT:
60
+ \u2022 libuild is zero-config - there is NO libuild.config.js file
61
+ \u2022 Configuration comes from your package.json (main, module, exports, etc.)
62
+ \u2022 Use --save to regenerate package.json fields based on built files
63
+ \u2022 Invalid bin/exports paths are automatically cleaned up with --save
64
+
59
65
  For publish command, all additional flags are forwarded to npm publish.
60
66
 
61
67
  Examples:
package/src/cli.js CHANGED
@@ -34,6 +34,12 @@ Options:
34
34
  --save Update root package.json to point to dist files
35
35
  --no-save Skip package.json updates (for publish command)
36
36
 
37
+ IMPORTANT:
38
+ \u2022 libuild is zero-config - there is NO libuild.config.js file
39
+ \u2022 Configuration comes from your package.json (main, module, exports, etc.)
40
+ \u2022 Use --save to regenerate package.json fields based on built files
41
+ \u2022 Invalid bin/exports paths are automatically cleaned up with --save
42
+
37
43
  For publish command, all additional flags are forwarded to npm publish.
38
44
 
39
45
  Examples:
package/src/libuild.cjs CHANGED
@@ -215345,7 +215345,6 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
215345
215345
  return exportEntry;
215346
215346
  }
215347
215347
  function expandExistingExport(existing, entryFromPath) {
215348
- var _a;
215349
215348
  if (typeof existing === "string") {
215350
215349
  if (existing === "./package.json" || existing.endsWith("/package.json")) {
215351
215350
  return existing;
@@ -215379,7 +215378,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
215379
215378
  throw new Error(`Export path '${existing}' must point to a valid entrypoint in src/ (e.g., './src/utils.js'). Nested directories and internal files (starting with '_' or '.') are not allowed.`);
215380
215379
  } else if (typeof existing === "object" && existing !== null) {
215381
215380
  if (options.formats.cjs && !existing.require && existing.import) {
215382
- const match = (_a = existing.import) == null ? void 0 : _a.match(/\.\/src\/([^/]+\.(?:ts|js))$/);
215381
+ const match = existing.import?.match(/\.\/src\/([^/]+\.(?:ts|js))$/);
215383
215382
  if (match) {
215384
215383
  const filename = match[1];
215385
215384
  if (!isValidEntrypoint(filename)) {
@@ -215509,6 +215508,10 @@ If you need to include pre-built executable files, use the files field instead:
215509
215508
  "files": ["scripts/my-tool.js"]`);
215510
215509
  }
215511
215510
  console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to dist/ directory: "${binPath}"
215511
+
215512
+ libuild is ZERO-CONFIG - there is no libuild.config.js file!
215513
+ Configuration comes from your package.json fields.
215514
+
215512
215515
  The libuild workflow is to point bin entries to src/ files and use --save to update paths.
215513
215516
  Consider changing to: "${srcPath}" and running 'libuild build --save'`);
215514
215517
  return;
@@ -215668,6 +215671,7 @@ function validatePath(inputPath, basePath) {
215668
215671
  }
215669
215672
  async function build2(cwd, save = false) {
215670
215673
  console.info("Building with libuild...");
215674
+ console.info(" Zero-config library build tool - configuration from package.json");
215671
215675
  const srcDir = Path3.join(cwd, "src");
215672
215676
  const distDir = Path3.join(cwd, "dist");
215673
215677
  const distSrcDir = Path3.join(distDir, "src");
@@ -215764,8 +215768,9 @@ async function build2(cwd, save = false) {
215764
215768
  sourcemap: false,
215765
215769
  external: externalDeps,
215766
215770
  platform: "node",
215767
- target: "node16",
215771
+ target: "node18",
215768
215772
  packages: "external",
215773
+ supported: { "import-attributes": true },
215769
215774
  plugins: [
215770
215775
  externalEntrypointsPlugin({
215771
215776
  entryNames,
@@ -215790,7 +215795,8 @@ async function build2(cwd, save = false) {
215790
215795
  sourcemap: false,
215791
215796
  external: externalDeps,
215792
215797
  platform: "node",
215793
- target: "node16",
215798
+ target: "node18",
215799
+ supported: { "import-attributes": true },
215794
215800
  plugins: [
215795
215801
  externalEntrypointsPlugin({
215796
215802
  entryNames,
@@ -215813,7 +215819,8 @@ async function build2(cwd, save = false) {
215813
215819
  sourcemap: false,
215814
215820
  external: externalDeps,
215815
215821
  platform: "node",
215816
- target: "node16",
215822
+ target: "node18",
215823
+ supported: { "import-attributes": true },
215817
215824
  plugins: [umdPlugin({ globalName })]
215818
215825
  });
215819
215826
  }
@@ -215830,7 +215837,8 @@ async function build2(cwd, save = false) {
215830
215837
  if (save) {
215831
215838
  console.info(" Removing stale exports from root package.json (--save mode)");
215832
215839
  } else {
215833
- console.warn(" Use --save to remove these from root package.json");
215840
+ console.warn(" libuild is ZERO-CONFIG - no libuild.config.js file needed!");
215841
+ console.warn(" Use 'libuild build --save' to clean up package.json automatically");
215834
215842
  }
215835
215843
  }
215836
215844
  if (cleanedPkg.files && Array.isArray(cleanedPkg.files)) {
@@ -215927,36 +215935,55 @@ async function build2(cwd, save = false) {
215927
215935
  const rootExports = {};
215928
215936
  for (const [key, value] of Object.entries(cleanedPkg.exports)) {
215929
215937
  if (typeof value === "string") {
215930
- rootExports[key] = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
215938
+ const distPath = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
215939
+ const fullPath = Path3.join(cwd, distPath);
215940
+ if (await fileExists(fullPath)) {
215941
+ rootExports[key] = distPath;
215942
+ }
215931
215943
  } else if (typeof value === "object" && value !== null) {
215932
- rootExports[key] = {};
215944
+ const cleanedValue = {};
215945
+ let hasValidPaths = false;
215933
215946
  for (const [subKey, subValue] of Object.entries(value)) {
215934
215947
  if (typeof subValue === "string") {
215935
- rootExports[key][subKey] = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
215948
+ const distPath = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
215949
+ const fullPath = Path3.join(cwd, distPath);
215950
+ if (await fileExists(fullPath)) {
215951
+ cleanedValue[subKey] = distPath;
215952
+ hasValidPaths = true;
215953
+ }
215936
215954
  }
215937
215955
  }
215956
+ if (hasValidPaths) {
215957
+ rootExports[key] = cleanedValue;
215958
+ }
215938
215959
  }
215939
215960
  }
215940
215961
  rootPkg2.exports = rootExports;
215941
215962
  if (rootPkg2.bin) {
215942
215963
  if (typeof rootPkg2.bin === "string") {
215943
- if (!rootPkg2.bin.startsWith("./dist/")) {
215944
- if (rootPkg2.bin.startsWith("dist/")) {
215945
- rootPkg2.bin = "./" + rootPkg2.bin;
215946
- } else {
215947
- rootPkg2.bin = "./" + Path3.join("dist", rootPkg2.bin);
215948
- }
215964
+ const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
215965
+ const fullPath = Path3.join(cwd, distPath);
215966
+ if (await fileExists(fullPath)) {
215967
+ rootPkg2.bin = distPath;
215968
+ } else {
215969
+ delete rootPkg2.bin;
215949
215970
  }
215950
215971
  } else {
215972
+ const cleanedBin = {};
215951
215973
  for (const [name, binPath] of Object.entries(rootPkg2.bin)) {
215952
- if (typeof binPath === "string" && !binPath.startsWith("./dist/")) {
215953
- if (binPath.startsWith("dist/")) {
215954
- rootPkg2.bin[name] = "./" + binPath;
215955
- } else {
215956
- rootPkg2.bin[name] = "./" + Path3.join("dist", binPath);
215974
+ if (typeof binPath === "string") {
215975
+ const distPath = binPath.startsWith("./dist/") ? binPath : binPath.startsWith("dist/") ? "./" + binPath : "./" + Path3.join("dist", binPath);
215976
+ const fullPath = Path3.join(cwd, distPath);
215977
+ if (await fileExists(fullPath)) {
215978
+ cleanedBin[name] = distPath;
215957
215979
  }
215958
215980
  }
215959
215981
  }
215982
+ if (Object.keys(cleanedBin).length > 0) {
215983
+ rootPkg2.bin = cleanedBin;
215984
+ } else {
215985
+ delete rootPkg2.bin;
215986
+ }
215960
215987
  }
215961
215988
  }
215962
215989
  if (pkg.files !== void 0) {
package/src/libuild.js CHANGED
@@ -324,7 +324,6 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
324
324
  return exportEntry;
325
325
  }
326
326
  function expandExistingExport(existing, entryFromPath) {
327
- var _a;
328
327
  if (typeof existing === "string") {
329
328
  if (existing === "./package.json" || existing.endsWith("/package.json")) {
330
329
  return existing;
@@ -358,7 +357,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
358
357
  throw new Error(`Export path '${existing}' must point to a valid entrypoint in src/ (e.g., './src/utils.js'). Nested directories and internal files (starting with '_' or '.') are not allowed.`);
359
358
  } else if (typeof existing === "object" && existing !== null) {
360
359
  if (options.formats.cjs && !existing.require && existing.import) {
361
- const match = (_a = existing.import) == null ? void 0 : _a.match(/\.\/src\/([^/]+\.(?:ts|js))$/);
360
+ const match = existing.import?.match(/\.\/src\/([^/]+\.(?:ts|js))$/);
362
361
  if (match) {
363
362
  const filename = match[1];
364
363
  if (!isValidEntrypoint(filename)) {
@@ -488,6 +487,10 @@ If you need to include pre-built executable files, use the files field instead:
488
487
  "files": ["scripts/my-tool.js"]`);
489
488
  }
490
489
  console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to dist/ directory: "${binPath}"
490
+
491
+ libuild is ZERO-CONFIG - there is no libuild.config.js file!
492
+ Configuration comes from your package.json fields.
493
+
491
494
  The libuild workflow is to point bin entries to src/ files and use --save to update paths.
492
495
  Consider changing to: "${srcPath}" and running 'libuild build --save'`);
493
496
  return;
@@ -647,6 +650,7 @@ function validatePath(inputPath, basePath) {
647
650
  }
648
651
  async function build2(cwd, save = false) {
649
652
  console.info("Building with libuild...");
653
+ console.info(" Zero-config library build tool - configuration from package.json");
650
654
  const srcDir = Path3.join(cwd, "src");
651
655
  const distDir = Path3.join(cwd, "dist");
652
656
  const distSrcDir = Path3.join(distDir, "src");
@@ -743,8 +747,9 @@ async function build2(cwd, save = false) {
743
747
  sourcemap: false,
744
748
  external: externalDeps,
745
749
  platform: "node",
746
- target: "node16",
750
+ target: "node18",
747
751
  packages: "external",
752
+ supported: { "import-attributes": true },
748
753
  plugins: [
749
754
  externalEntrypointsPlugin({
750
755
  entryNames,
@@ -769,7 +774,8 @@ async function build2(cwd, save = false) {
769
774
  sourcemap: false,
770
775
  external: externalDeps,
771
776
  platform: "node",
772
- target: "node16",
777
+ target: "node18",
778
+ supported: { "import-attributes": true },
773
779
  plugins: [
774
780
  externalEntrypointsPlugin({
775
781
  entryNames,
@@ -792,7 +798,8 @@ async function build2(cwd, save = false) {
792
798
  sourcemap: false,
793
799
  external: externalDeps,
794
800
  platform: "node",
795
- target: "node16",
801
+ target: "node18",
802
+ supported: { "import-attributes": true },
796
803
  plugins: [umdPlugin({ globalName })]
797
804
  });
798
805
  }
@@ -809,7 +816,8 @@ async function build2(cwd, save = false) {
809
816
  if (save) {
810
817
  console.info(" Removing stale exports from root package.json (--save mode)");
811
818
  } else {
812
- console.warn(" Use --save to remove these from root package.json");
819
+ console.warn(" libuild is ZERO-CONFIG - no libuild.config.js file needed!");
820
+ console.warn(" Use 'libuild build --save' to clean up package.json automatically");
813
821
  }
814
822
  }
815
823
  if (cleanedPkg.files && Array.isArray(cleanedPkg.files)) {
@@ -906,36 +914,55 @@ async function build2(cwd, save = false) {
906
914
  const rootExports = {};
907
915
  for (const [key, value] of Object.entries(cleanedPkg.exports)) {
908
916
  if (typeof value === "string") {
909
- rootExports[key] = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
917
+ const distPath = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
918
+ const fullPath = Path3.join(cwd, distPath);
919
+ if (await fileExists(fullPath)) {
920
+ rootExports[key] = distPath;
921
+ }
910
922
  } else if (typeof value === "object" && value !== null) {
911
- rootExports[key] = {};
923
+ const cleanedValue = {};
924
+ let hasValidPaths = false;
912
925
  for (const [subKey, subValue] of Object.entries(value)) {
913
926
  if (typeof subValue === "string") {
914
- rootExports[key][subKey] = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
927
+ const distPath = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
928
+ const fullPath = Path3.join(cwd, distPath);
929
+ if (await fileExists(fullPath)) {
930
+ cleanedValue[subKey] = distPath;
931
+ hasValidPaths = true;
932
+ }
915
933
  }
916
934
  }
935
+ if (hasValidPaths) {
936
+ rootExports[key] = cleanedValue;
937
+ }
917
938
  }
918
939
  }
919
940
  rootPkg2.exports = rootExports;
920
941
  if (rootPkg2.bin) {
921
942
  if (typeof rootPkg2.bin === "string") {
922
- if (!rootPkg2.bin.startsWith("./dist/")) {
923
- if (rootPkg2.bin.startsWith("dist/")) {
924
- rootPkg2.bin = "./" + rootPkg2.bin;
925
- } else {
926
- rootPkg2.bin = "./" + Path3.join("dist", rootPkg2.bin);
927
- }
943
+ const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
944
+ const fullPath = Path3.join(cwd, distPath);
945
+ if (await fileExists(fullPath)) {
946
+ rootPkg2.bin = distPath;
947
+ } else {
948
+ delete rootPkg2.bin;
928
949
  }
929
950
  } else {
951
+ const cleanedBin = {};
930
952
  for (const [name, binPath] of Object.entries(rootPkg2.bin)) {
931
- if (typeof binPath === "string" && !binPath.startsWith("./dist/")) {
932
- if (binPath.startsWith("dist/")) {
933
- rootPkg2.bin[name] = "./" + binPath;
934
- } else {
935
- rootPkg2.bin[name] = "./" + Path3.join("dist", binPath);
953
+ if (typeof binPath === "string") {
954
+ const distPath = binPath.startsWith("./dist/") ? binPath : binPath.startsWith("dist/") ? "./" + binPath : "./" + Path3.join("dist", binPath);
955
+ const fullPath = Path3.join(cwd, distPath);
956
+ if (await fileExists(fullPath)) {
957
+ cleanedBin[name] = distPath;
936
958
  }
937
959
  }
938
960
  }
961
+ if (Object.keys(cleanedBin).length > 0) {
962
+ rootPkg2.bin = cleanedBin;
963
+ } else {
964
+ delete rootPkg2.bin;
965
+ }
939
966
  }
940
967
  }
941
968
  if (pkg.files !== void 0) {