@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 +18 -0
- package/package.json +2 -2
- package/src/cli.cjs +6 -0
- package/src/cli.js +6 -0
- package/src/libuild.cjs +47 -20
- package/src/libuild.js +47 -20
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.
|
|
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": ">=
|
|
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 =
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
215944
|
+
const cleanedValue = {};
|
|
215945
|
+
let hasValidPaths = false;
|
|
215933
215946
|
for (const [subKey, subValue] of Object.entries(value)) {
|
|
215934
215947
|
if (typeof subValue === "string") {
|
|
215935
|
-
|
|
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
|
-
|
|
215944
|
-
|
|
215945
|
-
|
|
215946
|
-
|
|
215947
|
-
|
|
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"
|
|
215953
|
-
|
|
215954
|
-
|
|
215955
|
-
|
|
215956
|
-
|
|
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 =
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
923
|
+
const cleanedValue = {};
|
|
924
|
+
let hasValidPaths = false;
|
|
912
925
|
for (const [subKey, subValue] of Object.entries(value)) {
|
|
913
926
|
if (typeof subValue === "string") {
|
|
914
|
-
|
|
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
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
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"
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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) {
|