@b9g/libuild 0.1.9 → 0.1.11
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 +1 -1
- package/src/cli.cjs +6 -0
- package/src/cli.js +6 -0
- package/src/libuild.cjs +147 -58
- package/src/libuild.js +147 -58
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.11] - 2025-11-02
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **CRITICAL**: Workspace dependencies (workspace:*) are now properly resolved to actual version numbers during build
|
|
9
|
+
- Validation warnings for valid libuild output paths (dist/src/ files that libuild creates)
|
|
10
|
+
|
|
11
|
+
## [0.1.10] - 2025-10-29
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- Automatic cleanup of invalid bin/exports paths when using --save flag
|
|
15
|
+
- Clear messaging that libuild is zero-config with NO libuild.config.js file
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- --save now validates and removes bin/exports entries pointing to non-existent files
|
|
19
|
+
- Package.json fields are regenerated based on actual built files during --save
|
|
20
|
+
- Validation logic is now context-aware of --save flag to prevent warnings about configuration that libuild itself creates
|
|
21
|
+
- CLI argument parsing to prevent npm flags from being incorrectly treated as directory arguments
|
|
22
|
+
|
|
5
23
|
## [0.1.9] - 2025-10-29
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/package.json
CHANGED
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
|
@@ -215463,63 +215463,70 @@ function transformSrcToDist(value) {
|
|
|
215463
215463
|
}
|
|
215464
215464
|
return value;
|
|
215465
215465
|
}
|
|
215466
|
-
async function validateBinPaths(value,
|
|
215466
|
+
async function validateBinPaths(value, cwd, save, fieldName = "bin") {
|
|
215467
215467
|
if (typeof value === "string") {
|
|
215468
|
-
await validateSingleBinPath(value, fieldName,
|
|
215468
|
+
await validateSingleBinPath(value, fieldName, cwd, save);
|
|
215469
215469
|
} else if (typeof value === "object" && value !== null) {
|
|
215470
215470
|
for (const [key, val] of Object.entries(value)) {
|
|
215471
215471
|
if (typeof val === "string") {
|
|
215472
|
-
await validateSingleBinPath(val, `${fieldName}.${key}`,
|
|
215472
|
+
await validateSingleBinPath(val, `${fieldName}.${key}`, cwd, save);
|
|
215473
215473
|
}
|
|
215474
215474
|
}
|
|
215475
215475
|
}
|
|
215476
215476
|
}
|
|
215477
|
-
async function validateSingleBinPath(binPath, fieldName,
|
|
215478
|
-
if (
|
|
215479
|
-
|
|
215480
|
-
|
|
215481
|
-
|
|
215482
|
-
|
|
215483
|
-
|
|
215484
|
-
|
|
215485
|
-
|
|
215486
|
-
} else if (binPath.startsWith("dist/")) {
|
|
215487
|
-
srcPath = binPath.replace("dist/", "src/");
|
|
215488
|
-
} else {
|
|
215489
|
-
srcPath = "";
|
|
215477
|
+
async function validateSingleBinPath(binPath, fieldName, cwd, save) {
|
|
215478
|
+
if (save) {
|
|
215479
|
+
return;
|
|
215480
|
+
}
|
|
215481
|
+
if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/")) {
|
|
215482
|
+
const fullPath2 = Path3.join(cwd, binPath);
|
|
215483
|
+
const distExists = await fileExists(fullPath2);
|
|
215484
|
+
if (distExists) {
|
|
215485
|
+
return;
|
|
215490
215486
|
}
|
|
215491
|
-
const
|
|
215492
|
-
const
|
|
215493
|
-
const
|
|
215487
|
+
const srcPath = binPath.startsWith("./dist/src/") ? binPath.replace("./dist/src/", "src/") : binPath.replace("dist/src/", "src/");
|
|
215488
|
+
const basePath = srcPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
215489
|
+
const tsPath = Path3.join(cwd, basePath + ".ts");
|
|
215490
|
+
const jsPath = Path3.join(cwd, basePath + ".js");
|
|
215494
215491
|
const srcExists = await fileExists(tsPath) || await fileExists(jsPath);
|
|
215495
215492
|
if (!srcExists) {
|
|
215496
|
-
|
|
215497
|
-
|
|
215498
|
-
|
|
215499
|
-
|
|
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"]`);
|
|
215493
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" but neither the dist file nor corresponding src file exists.
|
|
215494
|
+
|
|
215495
|
+
Create "${srcPath}" and run 'libuild build --save' to update paths correctly.`);
|
|
215496
|
+
return;
|
|
215509
215497
|
}
|
|
215510
|
-
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to
|
|
215511
|
-
|
|
215512
|
-
|
|
215498
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist yet.
|
|
215499
|
+
|
|
215500
|
+
Run 'libuild build' to create the dist files, or use 'libuild build --save' to update the path to "${srcPath}".`);
|
|
215513
215501
|
return;
|
|
215514
215502
|
}
|
|
215515
|
-
if (binPath.startsWith("
|
|
215503
|
+
if (binPath.startsWith("dist/") || binPath.startsWith("./dist/")) {
|
|
215504
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" in dist/ directory.
|
|
215505
|
+
|
|
215506
|
+
libuild expects bin entries to point to src/ files. Consider changing to the corresponding src/ path and using --save.`);
|
|
215516
215507
|
return;
|
|
215517
215508
|
}
|
|
215518
|
-
|
|
215519
|
-
|
|
215520
|
-
|
|
215521
|
-
|
|
215509
|
+
const fullPath = Path3.join(cwd, binPath);
|
|
215510
|
+
const pathExists = await fileExists(fullPath);
|
|
215511
|
+
if (pathExists) {
|
|
215512
|
+
return;
|
|
215522
215513
|
}
|
|
215514
|
+
if (binPath.startsWith("src/") || binPath.startsWith("./src/")) {
|
|
215515
|
+
const basePath = fullPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
215516
|
+
const tsPath = basePath + ".ts";
|
|
215517
|
+
const jsPath = basePath + ".js";
|
|
215518
|
+
const tsExists = await fileExists(tsPath);
|
|
215519
|
+
const jsExists = await fileExists(jsPath);
|
|
215520
|
+
if (tsExists || jsExists) {
|
|
215521
|
+
return;
|
|
215522
|
+
}
|
|
215523
|
+
}
|
|
215524
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist
|
|
215525
|
+
|
|
215526
|
+
libuild is ZERO-CONFIG - there is no libuild.config.js file!
|
|
215527
|
+
Configuration comes from your package.json fields.
|
|
215528
|
+
|
|
215529
|
+
Use 'libuild build --save' to update package.json with correct dist/ paths automatically.`);
|
|
215523
215530
|
}
|
|
215524
215531
|
function transformBinPaths(value) {
|
|
215525
215532
|
if (typeof value === "string") {
|
|
@@ -215577,7 +215584,66 @@ function fixExportsForDist(obj) {
|
|
|
215577
215584
|
}
|
|
215578
215585
|
return obj;
|
|
215579
215586
|
}
|
|
215580
|
-
function
|
|
215587
|
+
async function resolveWorkspaceDependencies(dependencies, cwd) {
|
|
215588
|
+
if (!dependencies)
|
|
215589
|
+
return void 0;
|
|
215590
|
+
const resolved = {};
|
|
215591
|
+
for (const [depName, depVersion] of Object.entries(dependencies)) {
|
|
215592
|
+
if (depVersion.startsWith("workspace:")) {
|
|
215593
|
+
const resolvedVersion = await resolveWorkspaceVersion(depName, depVersion, cwd);
|
|
215594
|
+
resolved[depName] = resolvedVersion;
|
|
215595
|
+
} else {
|
|
215596
|
+
resolved[depName] = depVersion;
|
|
215597
|
+
}
|
|
215598
|
+
}
|
|
215599
|
+
return resolved;
|
|
215600
|
+
}
|
|
215601
|
+
async function resolveWorkspaceVersion(packageName, workspaceSpec, cwd) {
|
|
215602
|
+
try {
|
|
215603
|
+
if (workspaceSpec === "workspace:*") {
|
|
215604
|
+
const packageNameParts = packageName.replace("@", "").replace("/", "-");
|
|
215605
|
+
const packageBaseName = packageName.split("/").pop() || packageName;
|
|
215606
|
+
const possiblePaths = [
|
|
215607
|
+
`../packages/${packageNameParts}/package.json`,
|
|
215608
|
+
`../packages/${packageBaseName}/package.json`,
|
|
215609
|
+
`../${packageNameParts}/package.json`,
|
|
215610
|
+
`../${packageBaseName}/package.json`,
|
|
215611
|
+
`./packages/${packageNameParts}/package.json`,
|
|
215612
|
+
`./packages/${packageBaseName}/package.json`,
|
|
215613
|
+
`./${packageNameParts}/package.json`,
|
|
215614
|
+
`./${packageBaseName}/package.json`
|
|
215615
|
+
];
|
|
215616
|
+
for (const pkgPath of possiblePaths) {
|
|
215617
|
+
try {
|
|
215618
|
+
const resolvedPath = Path3.resolve(cwd, pkgPath);
|
|
215619
|
+
if (await fileExists(resolvedPath)) {
|
|
215620
|
+
const pkgContent = await FS3.readFile(resolvedPath, "utf-8");
|
|
215621
|
+
const pkgJson = JSON.parse(pkgContent);
|
|
215622
|
+
if (pkgJson.name === packageName) {
|
|
215623
|
+
console.info(` Resolved workspace:* dependency "${packageName}" to ^${pkgJson.version}`);
|
|
215624
|
+
return `^${pkgJson.version}`;
|
|
215625
|
+
}
|
|
215626
|
+
}
|
|
215627
|
+
} catch {
|
|
215628
|
+
continue;
|
|
215629
|
+
}
|
|
215630
|
+
}
|
|
215631
|
+
console.warn(`\u26A0\uFE0F WARNING: Could not resolve workspace dependency "${packageName}" - keeping as workspace:*`);
|
|
215632
|
+
console.warn(` Searched in: ${possiblePaths.map((p) => Path3.resolve(cwd, p)).join(", ")}`);
|
|
215633
|
+
return workspaceSpec;
|
|
215634
|
+
}
|
|
215635
|
+
const versionPart = workspaceSpec.replace("workspace:", "");
|
|
215636
|
+
if (versionPart !== "*") {
|
|
215637
|
+
console.info(` Resolved workspace:${versionPart} dependency "${packageName}" to ${versionPart}`);
|
|
215638
|
+
return versionPart;
|
|
215639
|
+
}
|
|
215640
|
+
return workspaceSpec;
|
|
215641
|
+
} catch (error) {
|
|
215642
|
+
console.warn(`\u26A0\uFE0F WARNING: Error resolving workspace dependency "${packageName}": ${error.message}`);
|
|
215643
|
+
return workspaceSpec;
|
|
215644
|
+
}
|
|
215645
|
+
}
|
|
215646
|
+
async function cleanPackageJSON(pkg, mainEntry, options, cwd) {
|
|
215581
215647
|
const cleaned = {
|
|
215582
215648
|
name: pkg.name,
|
|
215583
215649
|
version: pkg.version
|
|
@@ -215628,6 +215694,8 @@ function cleanPackageJSON(pkg, mainEntry, options) {
|
|
|
215628
215694
|
cleaned[field] = transformBinPaths(pkg[field]);
|
|
215629
215695
|
} else if (pathFields.includes(field)) {
|
|
215630
215696
|
cleaned[field] = transformSrcToDist(pkg[field]);
|
|
215697
|
+
} else if (field === "dependencies" || field === "devDependencies" || field === "peerDependencies" || field === "optionalDependencies") {
|
|
215698
|
+
cleaned[field] = await resolveWorkspaceDependencies(pkg[field], cwd);
|
|
215631
215699
|
} else {
|
|
215632
215700
|
cleaned[field] = pkg[field];
|
|
215633
215701
|
}
|
|
@@ -215667,6 +215735,7 @@ function validatePath(inputPath, basePath) {
|
|
|
215667
215735
|
}
|
|
215668
215736
|
async function build2(cwd, save = false) {
|
|
215669
215737
|
console.info("Building with libuild...");
|
|
215738
|
+
console.info(" Zero-config library build tool - configuration from package.json");
|
|
215670
215739
|
const srcDir = Path3.join(cwd, "src");
|
|
215671
215740
|
const distDir = Path3.join(cwd, "dist");
|
|
215672
215741
|
const distSrcDir = Path3.join(distDir, "src");
|
|
@@ -215676,7 +215745,7 @@ async function build2(cwd, save = false) {
|
|
|
215676
215745
|
const pkgPath = Path3.join(cwd, "package.json");
|
|
215677
215746
|
const pkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
|
|
215678
215747
|
if (pkg.bin) {
|
|
215679
|
-
await validateBinPaths(pkg.bin,
|
|
215748
|
+
await validateBinPaths(pkg.bin, cwd, save, "bin");
|
|
215680
215749
|
}
|
|
215681
215750
|
if (!pkg.private) {
|
|
215682
215751
|
console.warn("\u26A0\uFE0F WARNING: Root package.json is not private - this could lead to accidental publishing of development package.json");
|
|
@@ -215821,7 +215890,7 @@ async function build2(cwd, save = false) {
|
|
|
215821
215890
|
}
|
|
215822
215891
|
const autoDiscoveredFiles = [];
|
|
215823
215892
|
console.info(" Generating package.json...");
|
|
215824
|
-
const cleanedPkg = cleanPackageJSON(pkg, mainEntry, options);
|
|
215893
|
+
const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd);
|
|
215825
215894
|
const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
|
|
215826
215895
|
cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
|
|
215827
215896
|
if (exportsResult.staleExports.length > 0) {
|
|
@@ -215832,7 +215901,8 @@ async function build2(cwd, save = false) {
|
|
|
215832
215901
|
if (save) {
|
|
215833
215902
|
console.info(" Removing stale exports from root package.json (--save mode)");
|
|
215834
215903
|
} else {
|
|
215835
|
-
console.warn("
|
|
215904
|
+
console.warn(" libuild is ZERO-CONFIG - no libuild.config.js file needed!");
|
|
215905
|
+
console.warn(" Use 'libuild build --save' to clean up package.json automatically");
|
|
215836
215906
|
}
|
|
215837
215907
|
}
|
|
215838
215908
|
if (cleanedPkg.files && Array.isArray(cleanedPkg.files)) {
|
|
@@ -215929,36 +215999,55 @@ async function build2(cwd, save = false) {
|
|
|
215929
215999
|
const rootExports = {};
|
|
215930
216000
|
for (const [key, value] of Object.entries(cleanedPkg.exports)) {
|
|
215931
216001
|
if (typeof value === "string") {
|
|
215932
|
-
|
|
216002
|
+
const distPath = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
|
|
216003
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
216004
|
+
if (await fileExists(fullPath)) {
|
|
216005
|
+
rootExports[key] = distPath;
|
|
216006
|
+
}
|
|
215933
216007
|
} else if (typeof value === "object" && value !== null) {
|
|
215934
|
-
|
|
216008
|
+
const cleanedValue = {};
|
|
216009
|
+
let hasValidPaths = false;
|
|
215935
216010
|
for (const [subKey, subValue] of Object.entries(value)) {
|
|
215936
216011
|
if (typeof subValue === "string") {
|
|
215937
|
-
|
|
216012
|
+
const distPath = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
|
|
216013
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
216014
|
+
if (await fileExists(fullPath)) {
|
|
216015
|
+
cleanedValue[subKey] = distPath;
|
|
216016
|
+
hasValidPaths = true;
|
|
216017
|
+
}
|
|
215938
216018
|
}
|
|
215939
216019
|
}
|
|
216020
|
+
if (hasValidPaths) {
|
|
216021
|
+
rootExports[key] = cleanedValue;
|
|
216022
|
+
}
|
|
215940
216023
|
}
|
|
215941
216024
|
}
|
|
215942
216025
|
rootPkg2.exports = rootExports;
|
|
215943
216026
|
if (rootPkg2.bin) {
|
|
215944
216027
|
if (typeof rootPkg2.bin === "string") {
|
|
215945
|
-
|
|
215946
|
-
|
|
215947
|
-
|
|
215948
|
-
|
|
215949
|
-
|
|
215950
|
-
|
|
216028
|
+
const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
|
|
216029
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
216030
|
+
if (await fileExists(fullPath)) {
|
|
216031
|
+
rootPkg2.bin = distPath;
|
|
216032
|
+
} else {
|
|
216033
|
+
delete rootPkg2.bin;
|
|
215951
216034
|
}
|
|
215952
216035
|
} else {
|
|
216036
|
+
const cleanedBin = {};
|
|
215953
216037
|
for (const [name, binPath] of Object.entries(rootPkg2.bin)) {
|
|
215954
|
-
if (typeof binPath === "string"
|
|
215955
|
-
|
|
215956
|
-
|
|
215957
|
-
|
|
215958
|
-
|
|
216038
|
+
if (typeof binPath === "string") {
|
|
216039
|
+
const distPath = binPath.startsWith("./dist/") ? binPath : binPath.startsWith("dist/") ? "./" + binPath : "./" + Path3.join("dist", binPath);
|
|
216040
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
216041
|
+
if (await fileExists(fullPath)) {
|
|
216042
|
+
cleanedBin[name] = distPath;
|
|
215959
216043
|
}
|
|
215960
216044
|
}
|
|
215961
216045
|
}
|
|
216046
|
+
if (Object.keys(cleanedBin).length > 0) {
|
|
216047
|
+
rootPkg2.bin = cleanedBin;
|
|
216048
|
+
} else {
|
|
216049
|
+
delete rootPkg2.bin;
|
|
216050
|
+
}
|
|
215962
216051
|
}
|
|
215963
216052
|
}
|
|
215964
216053
|
if (pkg.files !== void 0) {
|
package/src/libuild.js
CHANGED
|
@@ -442,63 +442,70 @@ function transformSrcToDist(value) {
|
|
|
442
442
|
}
|
|
443
443
|
return value;
|
|
444
444
|
}
|
|
445
|
-
async function validateBinPaths(value,
|
|
445
|
+
async function validateBinPaths(value, cwd, save, fieldName = "bin") {
|
|
446
446
|
if (typeof value === "string") {
|
|
447
|
-
await validateSingleBinPath(value, fieldName,
|
|
447
|
+
await validateSingleBinPath(value, fieldName, cwd, save);
|
|
448
448
|
} else if (typeof value === "object" && value !== null) {
|
|
449
449
|
for (const [key, val] of Object.entries(value)) {
|
|
450
450
|
if (typeof val === "string") {
|
|
451
|
-
await validateSingleBinPath(val, `${fieldName}.${key}`,
|
|
451
|
+
await validateSingleBinPath(val, `${fieldName}.${key}`, cwd, save);
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
|
-
async function validateSingleBinPath(binPath, fieldName,
|
|
457
|
-
if (
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
} else if (binPath.startsWith("dist/")) {
|
|
466
|
-
srcPath = binPath.replace("dist/", "src/");
|
|
467
|
-
} else {
|
|
468
|
-
srcPath = "";
|
|
456
|
+
async function validateSingleBinPath(binPath, fieldName, cwd, save) {
|
|
457
|
+
if (save) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (binPath.startsWith("dist/src/") || binPath.startsWith("./dist/src/")) {
|
|
461
|
+
const fullPath2 = Path3.join(cwd, binPath);
|
|
462
|
+
const distExists = await fileExists(fullPath2);
|
|
463
|
+
if (distExists) {
|
|
464
|
+
return;
|
|
469
465
|
}
|
|
470
|
-
const
|
|
471
|
-
const
|
|
472
|
-
const
|
|
466
|
+
const srcPath = binPath.startsWith("./dist/src/") ? binPath.replace("./dist/src/", "src/") : binPath.replace("dist/src/", "src/");
|
|
467
|
+
const basePath = srcPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
468
|
+
const tsPath = Path3.join(cwd, basePath + ".ts");
|
|
469
|
+
const jsPath = Path3.join(cwd, basePath + ".js");
|
|
473
470
|
const srcExists = await fileExists(tsPath) || await fileExists(jsPath);
|
|
474
471
|
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"]`);
|
|
472
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" but neither the dist file nor corresponding src file exists.
|
|
473
|
+
|
|
474
|
+
Create "${srcPath}" and run 'libuild build --save' to update paths correctly.`);
|
|
475
|
+
return;
|
|
488
476
|
}
|
|
489
|
-
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to
|
|
490
|
-
|
|
491
|
-
|
|
477
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist yet.
|
|
478
|
+
|
|
479
|
+
Run 'libuild build' to create the dist files, or use 'libuild build --save' to update the path to "${srcPath}".`);
|
|
492
480
|
return;
|
|
493
481
|
}
|
|
494
|
-
if (binPath.startsWith("
|
|
482
|
+
if (binPath.startsWith("dist/") || binPath.startsWith("./dist/")) {
|
|
483
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" in dist/ directory.
|
|
484
|
+
|
|
485
|
+
libuild expects bin entries to point to src/ files. Consider changing to the corresponding src/ path and using --save.`);
|
|
495
486
|
return;
|
|
496
487
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
488
|
+
const fullPath = Path3.join(cwd, binPath);
|
|
489
|
+
const pathExists = await fileExists(fullPath);
|
|
490
|
+
if (pathExists) {
|
|
491
|
+
return;
|
|
501
492
|
}
|
|
493
|
+
if (binPath.startsWith("src/") || binPath.startsWith("./src/")) {
|
|
494
|
+
const basePath = fullPath.replace(/\.(js|cjs|mjs)$/, "");
|
|
495
|
+
const tsPath = basePath + ".ts";
|
|
496
|
+
const jsPath = basePath + ".js";
|
|
497
|
+
const tsExists = await fileExists(tsPath);
|
|
498
|
+
const jsExists = await fileExists(jsPath);
|
|
499
|
+
if (tsExists || jsExists) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
console.warn(`\u26A0\uFE0F WARNING: ${fieldName} field points to "${binPath}" which doesn't exist
|
|
504
|
+
|
|
505
|
+
libuild is ZERO-CONFIG - there is no libuild.config.js file!
|
|
506
|
+
Configuration comes from your package.json fields.
|
|
507
|
+
|
|
508
|
+
Use 'libuild build --save' to update package.json with correct dist/ paths automatically.`);
|
|
502
509
|
}
|
|
503
510
|
function transformBinPaths(value) {
|
|
504
511
|
if (typeof value === "string") {
|
|
@@ -556,7 +563,66 @@ function fixExportsForDist(obj) {
|
|
|
556
563
|
}
|
|
557
564
|
return obj;
|
|
558
565
|
}
|
|
559
|
-
function
|
|
566
|
+
async function resolveWorkspaceDependencies(dependencies, cwd) {
|
|
567
|
+
if (!dependencies)
|
|
568
|
+
return void 0;
|
|
569
|
+
const resolved = {};
|
|
570
|
+
for (const [depName, depVersion] of Object.entries(dependencies)) {
|
|
571
|
+
if (depVersion.startsWith("workspace:")) {
|
|
572
|
+
const resolvedVersion = await resolveWorkspaceVersion(depName, depVersion, cwd);
|
|
573
|
+
resolved[depName] = resolvedVersion;
|
|
574
|
+
} else {
|
|
575
|
+
resolved[depName] = depVersion;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return resolved;
|
|
579
|
+
}
|
|
580
|
+
async function resolveWorkspaceVersion(packageName, workspaceSpec, cwd) {
|
|
581
|
+
try {
|
|
582
|
+
if (workspaceSpec === "workspace:*") {
|
|
583
|
+
const packageNameParts = packageName.replace("@", "").replace("/", "-");
|
|
584
|
+
const packageBaseName = packageName.split("/").pop() || packageName;
|
|
585
|
+
const possiblePaths = [
|
|
586
|
+
`../packages/${packageNameParts}/package.json`,
|
|
587
|
+
`../packages/${packageBaseName}/package.json`,
|
|
588
|
+
`../${packageNameParts}/package.json`,
|
|
589
|
+
`../${packageBaseName}/package.json`,
|
|
590
|
+
`./packages/${packageNameParts}/package.json`,
|
|
591
|
+
`./packages/${packageBaseName}/package.json`,
|
|
592
|
+
`./${packageNameParts}/package.json`,
|
|
593
|
+
`./${packageBaseName}/package.json`
|
|
594
|
+
];
|
|
595
|
+
for (const pkgPath of possiblePaths) {
|
|
596
|
+
try {
|
|
597
|
+
const resolvedPath = Path3.resolve(cwd, pkgPath);
|
|
598
|
+
if (await fileExists(resolvedPath)) {
|
|
599
|
+
const pkgContent = await FS3.readFile(resolvedPath, "utf-8");
|
|
600
|
+
const pkgJson = JSON.parse(pkgContent);
|
|
601
|
+
if (pkgJson.name === packageName) {
|
|
602
|
+
console.info(` Resolved workspace:* dependency "${packageName}" to ^${pkgJson.version}`);
|
|
603
|
+
return `^${pkgJson.version}`;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
} catch {
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
console.warn(`\u26A0\uFE0F WARNING: Could not resolve workspace dependency "${packageName}" - keeping as workspace:*`);
|
|
611
|
+
console.warn(` Searched in: ${possiblePaths.map((p) => Path3.resolve(cwd, p)).join(", ")}`);
|
|
612
|
+
return workspaceSpec;
|
|
613
|
+
}
|
|
614
|
+
const versionPart = workspaceSpec.replace("workspace:", "");
|
|
615
|
+
if (versionPart !== "*") {
|
|
616
|
+
console.info(` Resolved workspace:${versionPart} dependency "${packageName}" to ${versionPart}`);
|
|
617
|
+
return versionPart;
|
|
618
|
+
}
|
|
619
|
+
return workspaceSpec;
|
|
620
|
+
} catch (error) {
|
|
621
|
+
console.warn(`\u26A0\uFE0F WARNING: Error resolving workspace dependency "${packageName}": ${error.message}`);
|
|
622
|
+
return workspaceSpec;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
async function cleanPackageJSON(pkg, mainEntry, options, cwd) {
|
|
560
626
|
const cleaned = {
|
|
561
627
|
name: pkg.name,
|
|
562
628
|
version: pkg.version
|
|
@@ -607,6 +673,8 @@ function cleanPackageJSON(pkg, mainEntry, options) {
|
|
|
607
673
|
cleaned[field] = transformBinPaths(pkg[field]);
|
|
608
674
|
} else if (pathFields.includes(field)) {
|
|
609
675
|
cleaned[field] = transformSrcToDist(pkg[field]);
|
|
676
|
+
} else if (field === "dependencies" || field === "devDependencies" || field === "peerDependencies" || field === "optionalDependencies") {
|
|
677
|
+
cleaned[field] = await resolveWorkspaceDependencies(pkg[field], cwd);
|
|
610
678
|
} else {
|
|
611
679
|
cleaned[field] = pkg[field];
|
|
612
680
|
}
|
|
@@ -646,6 +714,7 @@ function validatePath(inputPath, basePath) {
|
|
|
646
714
|
}
|
|
647
715
|
async function build2(cwd, save = false) {
|
|
648
716
|
console.info("Building with libuild...");
|
|
717
|
+
console.info(" Zero-config library build tool - configuration from package.json");
|
|
649
718
|
const srcDir = Path3.join(cwd, "src");
|
|
650
719
|
const distDir = Path3.join(cwd, "dist");
|
|
651
720
|
const distSrcDir = Path3.join(distDir, "src");
|
|
@@ -655,7 +724,7 @@ async function build2(cwd, save = false) {
|
|
|
655
724
|
const pkgPath = Path3.join(cwd, "package.json");
|
|
656
725
|
const pkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
|
|
657
726
|
if (pkg.bin) {
|
|
658
|
-
await validateBinPaths(pkg.bin,
|
|
727
|
+
await validateBinPaths(pkg.bin, cwd, save, "bin");
|
|
659
728
|
}
|
|
660
729
|
if (!pkg.private) {
|
|
661
730
|
console.warn("\u26A0\uFE0F WARNING: Root package.json is not private - this could lead to accidental publishing of development package.json");
|
|
@@ -800,7 +869,7 @@ async function build2(cwd, save = false) {
|
|
|
800
869
|
}
|
|
801
870
|
const autoDiscoveredFiles = [];
|
|
802
871
|
console.info(" Generating package.json...");
|
|
803
|
-
const cleanedPkg = cleanPackageJSON(pkg, mainEntry, options);
|
|
872
|
+
const cleanedPkg = await cleanPackageJSON(pkg, mainEntry, options, cwd);
|
|
804
873
|
const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
|
|
805
874
|
cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
|
|
806
875
|
if (exportsResult.staleExports.length > 0) {
|
|
@@ -811,7 +880,8 @@ async function build2(cwd, save = false) {
|
|
|
811
880
|
if (save) {
|
|
812
881
|
console.info(" Removing stale exports from root package.json (--save mode)");
|
|
813
882
|
} else {
|
|
814
|
-
console.warn("
|
|
883
|
+
console.warn(" libuild is ZERO-CONFIG - no libuild.config.js file needed!");
|
|
884
|
+
console.warn(" Use 'libuild build --save' to clean up package.json automatically");
|
|
815
885
|
}
|
|
816
886
|
}
|
|
817
887
|
if (cleanedPkg.files && Array.isArray(cleanedPkg.files)) {
|
|
@@ -908,36 +978,55 @@ async function build2(cwd, save = false) {
|
|
|
908
978
|
const rootExports = {};
|
|
909
979
|
for (const [key, value] of Object.entries(cleanedPkg.exports)) {
|
|
910
980
|
if (typeof value === "string") {
|
|
911
|
-
|
|
981
|
+
const distPath = value.startsWith("./dist/") ? value : `./dist${value.startsWith(".") ? value.slice(1) : value}`;
|
|
982
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
983
|
+
if (await fileExists(fullPath)) {
|
|
984
|
+
rootExports[key] = distPath;
|
|
985
|
+
}
|
|
912
986
|
} else if (typeof value === "object" && value !== null) {
|
|
913
|
-
|
|
987
|
+
const cleanedValue = {};
|
|
988
|
+
let hasValidPaths = false;
|
|
914
989
|
for (const [subKey, subValue] of Object.entries(value)) {
|
|
915
990
|
if (typeof subValue === "string") {
|
|
916
|
-
|
|
991
|
+
const distPath = subValue.startsWith("./dist/") ? subValue : `./dist${subValue.startsWith(".") ? subValue.slice(1) : subValue}`;
|
|
992
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
993
|
+
if (await fileExists(fullPath)) {
|
|
994
|
+
cleanedValue[subKey] = distPath;
|
|
995
|
+
hasValidPaths = true;
|
|
996
|
+
}
|
|
917
997
|
}
|
|
918
998
|
}
|
|
999
|
+
if (hasValidPaths) {
|
|
1000
|
+
rootExports[key] = cleanedValue;
|
|
1001
|
+
}
|
|
919
1002
|
}
|
|
920
1003
|
}
|
|
921
1004
|
rootPkg2.exports = rootExports;
|
|
922
1005
|
if (rootPkg2.bin) {
|
|
923
1006
|
if (typeof rootPkg2.bin === "string") {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1007
|
+
const distPath = rootPkg2.bin.startsWith("./dist/") ? rootPkg2.bin : rootPkg2.bin.startsWith("dist/") ? "./" + rootPkg2.bin : "./" + Path3.join("dist", rootPkg2.bin);
|
|
1008
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
1009
|
+
if (await fileExists(fullPath)) {
|
|
1010
|
+
rootPkg2.bin = distPath;
|
|
1011
|
+
} else {
|
|
1012
|
+
delete rootPkg2.bin;
|
|
930
1013
|
}
|
|
931
1014
|
} else {
|
|
1015
|
+
const cleanedBin = {};
|
|
932
1016
|
for (const [name, binPath] of Object.entries(rootPkg2.bin)) {
|
|
933
|
-
if (typeof binPath === "string"
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1017
|
+
if (typeof binPath === "string") {
|
|
1018
|
+
const distPath = binPath.startsWith("./dist/") ? binPath : binPath.startsWith("dist/") ? "./" + binPath : "./" + Path3.join("dist", binPath);
|
|
1019
|
+
const fullPath = Path3.join(cwd, distPath);
|
|
1020
|
+
if (await fileExists(fullPath)) {
|
|
1021
|
+
cleanedBin[name] = distPath;
|
|
938
1022
|
}
|
|
939
1023
|
}
|
|
940
1024
|
}
|
|
1025
|
+
if (Object.keys(cleanedBin).length > 0) {
|
|
1026
|
+
rootPkg2.bin = cleanedBin;
|
|
1027
|
+
} else {
|
|
1028
|
+
delete rootPkg2.bin;
|
|
1029
|
+
}
|
|
941
1030
|
}
|
|
942
1031
|
}
|
|
943
1032
|
if (pkg.files !== void 0) {
|