@b9g/libuild 0.1.3 → 0.1.5

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
@@ -35,19 +35,17 @@ __export(libuild_exports, {
35
35
  transformSrcToDist: () => transformSrcToDist
36
36
  });
37
37
  module.exports = __toCommonJS(libuild_exports);
38
- var FS2 = __toESM(require("fs/promises"), 1);
39
- var Path2 = __toESM(require("path"), 1);
38
+ var FS3 = __toESM(require("fs/promises"), 1);
39
+ var Path3 = __toESM(require("path"), 1);
40
40
  var import_child_process = require("child_process");
41
41
  var ESBuild = __toESM(require("esbuild"), 1);
42
- var TS = __toESM(require("typescript"), 1);
43
42
 
44
- // src/umd-plugin.ts
43
+ // src/plugins/umd.ts
45
44
  var FS = __toESM(require("fs/promises"), 1);
46
45
  var Path = __toESM(require("path"), 1);
47
- var import_magic_string = __toESM(require("magic-string"), 1);
48
46
  function umdPlugin(options) {
49
47
  return {
50
- name: "umd-wrapper",
48
+ name: "umd",
51
49
  setup(build3) {
52
50
  build3.onEnd(async (result) => {
53
51
  if (result.errors.length > 0)
@@ -57,7 +55,7 @@ function umdPlugin(options) {
57
55
  const files = await FS.readdir(outputDir);
58
56
  for (const file of files) {
59
57
  if (file.endsWith(".js") && !file.endsWith(".js.map")) {
60
- await wrapWithUmd(Path.join(outputDir, file), options.globalName);
58
+ await wrapWithUMD(Path.join(outputDir, file), options.globalName);
61
59
  }
62
60
  }
63
61
  }
@@ -65,20 +63,9 @@ function umdPlugin(options) {
65
63
  }
66
64
  };
67
65
  }
68
- async function wrapWithUmd(filePath, globalName) {
66
+ async function wrapWithUMD(filePath, globalName) {
69
67
  const code = await FS.readFile(filePath, "utf-8");
70
- const ms = new import_magic_string.default(code);
71
- const sourcemapComment = code.match(/\/\/# sourceMappingURL=.+$/m);
72
- if (sourcemapComment) {
73
- const index = code.lastIndexOf(sourcemapComment[0]);
74
- ms.remove(index, index + sourcemapComment[0].length);
75
- }
76
- const exportsMatch = code.match(/\nmodule\.exports\s*=\s*([^;]+);?\s*$/);
77
- if (exportsMatch) {
78
- const index = code.lastIndexOf(exportsMatch[0]);
79
- ms.overwrite(index, index + exportsMatch[0].length, `
80
- return ${exportsMatch[1]};`);
81
- }
68
+ let modifiedCode = code.replace(/\nmodule\.exports\s*=\s*([^;]+);?\s*$/, "\nreturn $1;");
82
69
  const umdHeader = `(function (root, factory) {
83
70
  if (typeof define === 'function' && define.amd) {
84
71
  // AMD
@@ -94,18 +81,144 @@ return ${exportsMatch[1]};`);
94
81
  `;
95
82
  const umdFooter = `
96
83
  }));`;
97
- ms.prepend(umdHeader);
98
- ms.append(umdFooter);
99
- const result = ms.toString();
100
- const map = ms.generateMap({
101
- file: Path.basename(filePath),
102
- source: Path.basename(filePath).replace(".js", ".ts"),
103
- includeContent: true
104
- });
84
+ const result = umdHeader + modifiedCode + umdFooter;
105
85
  await FS.writeFile(filePath, result);
106
- await FS.writeFile(filePath + ".map", map.toString());
107
- await FS.writeFile(filePath, result + `
108
- //# sourceMappingURL=${Path.basename(filePath)}.map`);
86
+ }
87
+
88
+ // src/plugins/external.ts
89
+ function externalEntrypointsPlugin(options) {
90
+ return {
91
+ name: "external-entrypoints",
92
+ setup(build3) {
93
+ const { entryNames, currentEntry, outputExtension } = options;
94
+ const externalEntries = currentEntry ? entryNames.filter((name) => name !== currentEntry) : entryNames;
95
+ build3.onResolve({ filter: /^\.\// }, (args) => {
96
+ const withoutExt = args.path.replace(/\.(ts|js)$/, "");
97
+ const entryName = withoutExt.replace(/^\.\//, "");
98
+ if (externalEntries.includes(entryName)) {
99
+ return {
100
+ path: `./${entryName}${outputExtension}`,
101
+ external: true
102
+ };
103
+ }
104
+ });
105
+ }
106
+ };
107
+ }
108
+
109
+ // src/plugins/dts.ts
110
+ var FS2 = __toESM(require("fs/promises"), 1);
111
+ var Path2 = __toESM(require("path"), 1);
112
+ function dtsPlugin(options) {
113
+ return {
114
+ name: "dts",
115
+ setup(build3) {
116
+ const entryFiles = [];
117
+ build3.onLoad({ filter: /\.tsx?$/ }, async (args) => {
118
+ if (!entryFiles.includes(args.path)) {
119
+ entryFiles.push(args.path);
120
+ }
121
+ return void 0;
122
+ });
123
+ build3.onEnd(async (result) => {
124
+ if (result.errors.length > 0) {
125
+ return;
126
+ }
127
+ let TS;
128
+ try {
129
+ TS = await import("typescript");
130
+ } catch {
131
+ return;
132
+ }
133
+ const tsFiles = entryFiles.filter((file) => {
134
+ if (!file.endsWith(".ts"))
135
+ return false;
136
+ return options.entryPoints.some((entryPoint) => {
137
+ const normalizedEntry = Path2.resolve(entryPoint);
138
+ const normalizedFile = Path2.resolve(file);
139
+ return normalizedEntry === normalizedFile;
140
+ });
141
+ });
142
+ if (tsFiles.length === 0) {
143
+ return;
144
+ }
145
+ try {
146
+ const compilerOptions = {
147
+ declaration: true,
148
+ emitDeclarationOnly: true,
149
+ outDir: options.outDir,
150
+ rootDir: options.rootDir,
151
+ skipLibCheck: true,
152
+ esModuleInterop: true,
153
+ target: TS.ScriptTarget.ES2020,
154
+ module: TS.ModuleKind.ESNext,
155
+ isolatedModules: true,
156
+ // Prevent cross-file type dependencies
157
+ noResolve: true
158
+ // Don't resolve imports - only process the specific files
159
+ };
160
+ const program = TS.createProgram(tsFiles, compilerOptions);
161
+ const emitResult = program.emit();
162
+ if (emitResult.diagnostics.length > 0) {
163
+ const diagnostics = TS.formatDiagnosticsWithColorAndContext(emitResult.diagnostics, {
164
+ getCanonicalFileName: (path) => path,
165
+ getCurrentDirectory: () => process.cwd(),
166
+ getNewLine: () => "\n"
167
+ });
168
+ result.errors.push({
169
+ id: "typescript-declarations",
170
+ pluginName: "dts",
171
+ text: `TypeScript declaration generation failed:
172
+ ${diagnostics}`,
173
+ location: null,
174
+ notes: [],
175
+ detail: void 0
176
+ });
177
+ }
178
+ } catch (error) {
179
+ result.errors.push({
180
+ id: "typescript-plugin-error",
181
+ pluginName: "dts",
182
+ text: `TypeScript plugin error: ${error.message}`,
183
+ location: null,
184
+ notes: [],
185
+ detail: void 0
186
+ });
187
+ }
188
+ await addTripleSlashReferences(tsFiles, options.outDir);
189
+ });
190
+ }
191
+ };
192
+ }
193
+ async function addTripleSlashReferences(tsFiles, outDir) {
194
+ for (const tsFile of tsFiles) {
195
+ const baseName = Path2.basename(tsFile, Path2.extname(tsFile));
196
+ const jsPath = Path2.join(outDir, `${baseName}.js`);
197
+ const dtsPath = Path2.join(outDir, `${baseName}.d.ts`);
198
+ const [jsExists, dtsExists] = await Promise.all([
199
+ FS2.access(jsPath).then(() => true).catch(() => false),
200
+ FS2.access(dtsPath).then(() => true).catch(() => false)
201
+ ]);
202
+ if (!jsExists || !dtsExists)
203
+ continue;
204
+ const content = await FS2.readFile(jsPath, "utf-8");
205
+ const referenceComment = `/// <reference types="./${baseName}.d.ts" />`;
206
+ let modifiedContent;
207
+ if (content.startsWith("#!")) {
208
+ const firstNewline = content.indexOf("\n");
209
+ if (firstNewline !== -1) {
210
+ modifiedContent = content.slice(0, firstNewline + 1) + `${referenceComment}
211
+ ` + content.slice(firstNewline + 1);
212
+ } else {
213
+ modifiedContent = content + `
214
+ ${referenceComment}`;
215
+ }
216
+ } else {
217
+ modifiedContent = `${referenceComment}
218
+ ${content}`;
219
+ }
220
+ await FS2.writeFile(jsPath, modifiedContent);
221
+ }
109
222
  }
110
223
 
111
224
  // src/libuild.ts
@@ -120,11 +233,15 @@ function isValidEntrypoint(filename) {
120
233
  return false;
121
234
  return true;
122
235
  }
123
- async function findEntryPoints(srcDir) {
124
- const files = await FS2.readdir(srcDir);
125
- return files.filter(isValidEntrypoint).map((file) => Path2.basename(file, Path2.extname(file))).sort();
236
+ async function findEntrypoints(srcDir) {
237
+ const files = await FS3.readdir(srcDir);
238
+ return files.filter(isValidEntrypoint).map((file) => Path3.basename(file, Path3.extname(file))).sort();
126
239
  }
127
- async function detectMainEntry(pkg, entries) {
240
+ function detectMainEntry(pkg, entries) {
241
+ function extractEntryFromPath(path) {
242
+ const match = path.match(/\.\/src\/([^.]+)/);
243
+ return match ? match[1] : void 0;
244
+ }
128
245
  if (pkg.exports && pkg.exports["."]) {
129
246
  const dotExport = pkg.exports["."];
130
247
  let importPath;
@@ -134,18 +251,24 @@ async function detectMainEntry(pkg, entries) {
134
251
  importPath = dotExport.import;
135
252
  }
136
253
  if (importPath) {
137
- const match = importPath.match(/\.\/src\/([^.]+)/);
138
- if (match && entries.includes(match[1])) {
139
- return match[1];
254
+ const entry = extractEntryFromPath(importPath);
255
+ if (entry && entries.includes(entry)) {
256
+ return entry;
140
257
  }
141
258
  }
142
259
  }
143
260
  if (pkg.main && typeof pkg.main === "string") {
144
- const mainBase = Path2.basename(pkg.main, Path2.extname(pkg.main));
261
+ const mainBase = Path3.basename(pkg.main, Path3.extname(pkg.main));
145
262
  if (entries.includes(mainBase)) {
146
263
  return mainBase;
147
264
  }
148
265
  }
266
+ if (pkg.module && typeof pkg.module === "string") {
267
+ const moduleBase = Path3.basename(pkg.module, Path3.extname(pkg.module));
268
+ if (entries.includes(moduleBase)) {
269
+ return moduleBase;
270
+ }
271
+ }
149
272
  if (entries.includes("index")) {
150
273
  return "index";
151
274
  }
@@ -236,7 +359,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
236
359
  if (!isValidEntrypoint(filename)) {
237
360
  throw new Error(`Export path '${existing}' references '${filename}' which is not a valid entrypoint. Valid entrypoints cannot start with '_' or '.' and must be .ts/.js files in src/.`);
238
361
  }
239
- const entry = Path2.basename(filename, Path2.extname(filename));
362
+ const entry = Path3.basename(filename, Path3.extname(filename));
240
363
  return options.formats.cjs ? {
241
364
  types: `./src/${entry}.d.ts`,
242
365
  import: existing,
@@ -265,7 +388,7 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
265
388
  if (!isValidEntrypoint(filename)) {
266
389
  throw new Error(`Export import path '${existing.import}' references '${filename}' which is not a valid entrypoint. Valid entrypoints cannot start with '_' or '.' and must be .ts/.js files in src/.`);
267
390
  }
268
- const entry = Path2.basename(filename, Path2.extname(filename));
391
+ const entry = Path3.basename(filename, Path3.extname(filename));
269
392
  return {
270
393
  ...existing,
271
394
  types: existing.types || `./src/${entry}.d.ts`,
@@ -313,14 +436,6 @@ function generateExports(entries, mainEntry, options, existingExports = {}) {
313
436
  if (!exports2[`${key}.js`]) {
314
437
  exports2[`${key}.js`] = exports2[key];
315
438
  }
316
- if (entry === "jsx-runtime") {
317
- if (!exports2["./jsx-dev-runtime"]) {
318
- exports2["./jsx-dev-runtime"] = exports2[key];
319
- }
320
- if (!exports2["./jsx-dev-runtime.js"]) {
321
- exports2["./jsx-dev-runtime.js"] = exports2[key];
322
- }
323
- }
324
439
  }
325
440
  if (options.formats.umd && !exports2["./umd"]) {
326
441
  exports2["./umd"] = {
@@ -352,6 +467,30 @@ function transformSrcToDist(value) {
352
467
  }
353
468
  return value;
354
469
  }
470
+ function transformBinPaths(value) {
471
+ if (typeof value === "string") {
472
+ if (value.startsWith("./dist/src/")) {
473
+ return value.replace("./dist/", "");
474
+ }
475
+ if (value.startsWith("dist/src/")) {
476
+ return value.replace("dist/", "");
477
+ }
478
+ if (value.startsWith("./src/")) {
479
+ return value.replace("./", "");
480
+ }
481
+ if (value.startsWith("src/") || value === "src") {
482
+ return value;
483
+ }
484
+ return value;
485
+ } else if (typeof value === "object" && value !== null) {
486
+ const transformed = {};
487
+ for (const [key, val] of Object.entries(value)) {
488
+ transformed[key] = transformBinPaths(val);
489
+ }
490
+ return transformed;
491
+ }
492
+ return value;
493
+ }
355
494
  function fixExportsForDist(obj) {
356
495
  if (typeof obj === "string") {
357
496
  if (obj.includes("/dist/") && obj.includes("/src/")) {
@@ -374,6 +513,8 @@ function fixExportsForDist(obj) {
374
513
  for (const [key, val] of Object.entries(obj)) {
375
514
  if (key === "files" && Array.isArray(val)) {
376
515
  fixed[key] = val.filter((file) => file !== "dist/" && file !== "dist").concat(val.includes("dist/") || val.includes("dist") ? ["src/"] : []);
516
+ } else if (key === "bin") {
517
+ fixed[key] = val;
377
518
  } else {
378
519
  fixed[key] = fixExportsForDist(val);
379
520
  }
@@ -401,7 +542,9 @@ function cleanPackageJSON(pkg, mainEntry, options) {
401
542
  "bin",
402
543
  "scripts",
403
544
  "dependencies",
545
+ "devDependencies",
404
546
  "peerDependencies",
547
+ "peerDependenciesMeta",
405
548
  "optionalDependencies",
406
549
  "bundledDependencies",
407
550
  "engines",
@@ -428,7 +571,7 @@ function cleanPackageJSON(pkg, mainEntry, options) {
428
571
  cleaned[field] = transformSrcToDist(filteredScripts);
429
572
  }
430
573
  } else if (field === "bin") {
431
- cleaned[field] = transformSrcToDist(pkg[field]);
574
+ cleaned[field] = transformBinPaths(pkg[field]);
432
575
  } else if (pathFields.includes(field)) {
433
576
  cleaned[field] = transformSrcToDist(pkg[field]);
434
577
  } else {
@@ -448,36 +591,50 @@ function cleanPackageJSON(pkg, mainEntry, options) {
448
591
  }
449
592
  async function fileExists(filePath) {
450
593
  try {
451
- await FS2.access(filePath);
594
+ await FS3.access(filePath);
452
595
  return true;
453
596
  } catch {
454
597
  return false;
455
598
  }
456
599
  }
600
+ function validatePath(inputPath, basePath) {
601
+ if (Path3.isAbsolute(inputPath)) {
602
+ throw new Error(`Absolute paths are not allowed: ${inputPath}`);
603
+ }
604
+ if (inputPath.includes("..")) {
605
+ throw new Error(`Path traversal is not allowed: ${inputPath}`);
606
+ }
607
+ const resolvedPath = Path3.resolve(basePath, inputPath);
608
+ const resolvedBase = Path3.resolve(basePath);
609
+ if (!resolvedPath.startsWith(resolvedBase + Path3.sep) && resolvedPath !== resolvedBase) {
610
+ throw new Error(`Path ${inputPath} resolves outside the project directory`);
611
+ }
612
+ return resolvedPath;
613
+ }
457
614
  async function build2(cwd, save = false) {
458
- console.log("Building with libuild...");
459
- const srcDir = Path2.join(cwd, "src");
460
- const distDir = Path2.join(cwd, "dist");
461
- const distSrcDir = Path2.join(distDir, "src");
615
+ console.info("Building with libuild...");
616
+ const srcDir = Path3.join(cwd, "src");
617
+ const distDir = Path3.join(cwd, "dist");
618
+ const distSrcDir = Path3.join(distDir, "src");
462
619
  if (!await fileExists(srcDir)) {
463
620
  throw new Error("No src/ directory found");
464
621
  }
465
- const pkgPath = Path2.join(cwd, "package.json");
466
- const pkg = JSON.parse(await FS2.readFile(pkgPath, "utf-8"));
622
+ const pkgPath = Path3.join(cwd, "package.json");
623
+ const pkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
467
624
  if (!pkg.private) {
468
625
  console.warn("\u26A0\uFE0F WARNING: Root package.json is not private - this could lead to accidental publishing of development package.json");
469
626
  console.warn(" Consider setting 'private: true' in your root package.json");
470
627
  }
471
- const gitignorePath = Path2.join(cwd, ".gitignore");
628
+ const gitignorePath = Path3.join(cwd, ".gitignore");
472
629
  if (await fileExists(gitignorePath)) {
473
- const gitignoreContent = await FS2.readFile(gitignorePath, "utf-8");
630
+ const gitignoreContent = await FS3.readFile(gitignorePath, "utf-8");
474
631
  const isDistIgnored = gitignoreContent.includes("dist/") || gitignoreContent.includes("/dist") || gitignoreContent.includes("dist\n") || gitignoreContent.includes("dist\r\n");
475
632
  if (!isDistIgnored) {
476
633
  console.warn("\u26A0\uFE0F WARNING: dist/ directory is not in .gitignore - built files should not be committed");
477
634
  console.warn(" Add 'dist/' to your .gitignore file");
478
635
  }
479
636
  }
480
- const entries = await findEntryPoints(srcDir);
637
+ const entries = await findEntrypoints(srcDir);
481
638
  if (entries.length === 0) {
482
639
  throw new Error("No entry points found in src/");
483
640
  }
@@ -490,23 +647,40 @@ async function build2(cwd, save = false) {
490
647
  umd: entries.includes("umd")
491
648
  }
492
649
  };
493
- const mainEntry = await detectMainEntry(pkg, entries);
494
- console.log(" Found entries:", entries.join(", "));
495
- console.log(" Main entry:", mainEntry);
650
+ const mainEntry = detectMainEntry(pkg, entries);
651
+ console.info(" Found entries:", entries.join(", "));
652
+ console.info(" Main entry:", mainEntry);
496
653
  if (options.formats.cjs) {
497
- console.log(" Formats: ESM, CJS" + (options.formats.umd ? ", UMD" : ""));
654
+ console.info(" Formats: ESM, CJS" + (options.formats.umd ? ", UMD" : ""));
498
655
  } else {
499
- console.log(" Formats: ESM" + (options.formats.umd ? ", UMD" : "") + " (no main field - CJS disabled)");
656
+ console.info(" Formats: ESM" + (options.formats.umd ? ", UMD" : "") + " (no main field - CJS disabled)");
500
657
  }
501
- if (await fileExists(distDir)) {
502
- await FS2.rm(distDir, { recursive: true });
658
+ const tempDistDir = `${distDir}.tmp.${Date.now()}.${Math.random().toString(36).substr(2, 9)}`;
659
+ try {
660
+ await FS3.mkdir(tempDistDir, { recursive: true });
661
+ if (await fileExists(distDir)) {
662
+ await FS3.rm(distDir, { recursive: true });
663
+ }
664
+ await FS3.rename(tempDistDir, distDir);
665
+ } catch (error) {
666
+ try {
667
+ if (await fileExists(tempDistDir)) {
668
+ await FS3.rm(tempDistDir, { recursive: true });
669
+ }
670
+ } catch {
671
+ }
672
+ throw error;
503
673
  }
504
- await FS2.mkdir(distDir, { recursive: true });
674
+ const externalDeps = [
675
+ ...Object.keys(pkg.dependencies || {}),
676
+ ...Object.keys(pkg.peerDependencies || {}),
677
+ ...Object.keys(pkg.optionalDependencies || {})
678
+ ];
505
679
  const entryPoints = [];
506
680
  const umdEntries = [];
507
681
  for (const entry of entries) {
508
- const entryPath = Path2.join(srcDir, `${entry}.ts`);
509
- const jsEntryPath = Path2.join(srcDir, `${entry}.js`);
682
+ const entryPath = Path3.join(srcDir, `${entry}.ts`);
683
+ const jsEntryPath = Path3.join(srcDir, `${entry}.js`);
510
684
  const actualPath = await fileExists(entryPath) ? entryPath : jsEntryPath;
511
685
  if (!await fileExists(actualPath)) {
512
686
  throw new Error(`Entry point file not found: ${actualPath}. Expected ${entry}.ts or ${entry}.js in src/ directory.`);
@@ -518,105 +692,75 @@ async function build2(cwd, save = false) {
518
692
  }
519
693
  }
520
694
  if (entryPoints.length > 0) {
521
- console.log(` Building ${entryPoints.length} entries (ESM)...`);
695
+ const entryNames = entryPoints.map((path) => {
696
+ const name = Path3.basename(path, Path3.extname(path));
697
+ return name;
698
+ });
699
+ console.info(` Building ${entryPoints.length} entries (ESM)...`);
522
700
  await ESBuild.build({
523
701
  entryPoints,
524
702
  outdir: distSrcDir,
525
703
  format: "esm",
526
- entryNames: "[name]",
527
704
  outExtension: { ".js": ".js" },
528
705
  bundle: true,
529
- splitting: true,
530
- // Enable shared chunk extraction
531
706
  minify: false,
532
- sourcemap: true,
533
- external: Object.keys(pkg.dependencies || {}),
707
+ sourcemap: false,
708
+ external: externalDeps,
534
709
  platform: "node",
535
- target: "node16"
710
+ target: "node16",
711
+ plugins: [
712
+ externalEntrypointsPlugin({
713
+ entryNames,
714
+ outputExtension: ".js"
715
+ }),
716
+ dtsPlugin({
717
+ outDir: distSrcDir,
718
+ rootDir: srcDir,
719
+ entryPoints
720
+ })
721
+ ]
536
722
  });
537
723
  if (options.formats.cjs) {
538
- console.log(` Building ${entryPoints.length} entries (CJS)...`);
724
+ console.info(` Building ${entryPoints.length} entries (CJS)...`);
539
725
  await ESBuild.build({
540
726
  entryPoints,
541
727
  outdir: distSrcDir,
542
728
  format: "cjs",
543
- entryNames: "[name]",
544
729
  outExtension: { ".js": ".cjs" },
545
730
  bundle: true,
546
731
  minify: false,
547
- sourcemap: true,
548
- external: Object.keys(pkg.dependencies || {}),
732
+ sourcemap: false,
733
+ external: externalDeps,
549
734
  platform: "node",
550
- target: "node16"
551
- // Note: CJS doesn't support splitting, but building together still helps with consistency
735
+ target: "node16",
736
+ plugins: [
737
+ externalEntrypointsPlugin({
738
+ entryNames,
739
+ outputExtension: ".cjs"
740
+ })
741
+ ]
552
742
  });
553
743
  }
554
744
  }
555
745
  for (const umdPath of umdEntries) {
556
- const entry = Path2.basename(umdPath, Path2.extname(umdPath));
557
- console.log(` Building ${entry} (UMD)...`);
746
+ const entry = Path3.basename(umdPath, Path3.extname(umdPath));
747
+ console.info(` Building ${entry} (UMD)...`);
558
748
  const globalName = pkg.name.includes("/") ? pkg.name.split("/").pop().replace(/-/g, "").charAt(0).toUpperCase() + pkg.name.split("/").pop().replace(/-/g, "").slice(1) : pkg.name.replace(/-/g, "").charAt(0).toUpperCase() + pkg.name.replace(/-/g, "").slice(1);
559
749
  await ESBuild.build({
560
750
  entryPoints: [umdPath],
561
751
  outdir: distSrcDir,
562
752
  format: "cjs",
563
- entryNames: "[name]",
564
753
  bundle: true,
565
754
  minify: false,
566
- sourcemap: true,
567
- external: Object.keys(pkg.dependencies || {}),
755
+ sourcemap: false,
756
+ external: externalDeps,
568
757
  platform: "node",
569
758
  target: "node16",
570
759
  plugins: [umdPlugin({ globalName })]
571
760
  });
572
761
  }
573
- console.log(" Generating TypeScript declarations...");
574
- const allTsFiles = [...entryPoints, ...umdEntries].filter((file) => file.endsWith(".ts"));
575
- if (allTsFiles.length > 0) {
576
- const compilerOptions = {
577
- declaration: true,
578
- emitDeclarationOnly: true,
579
- outDir: distSrcDir,
580
- rootDir: srcDir,
581
- skipLibCheck: true,
582
- esModuleInterop: true,
583
- target: TS.ScriptTarget.ES2020,
584
- module: TS.ModuleKind.ESNext
585
- };
586
- const program = TS.createProgram(allTsFiles, compilerOptions);
587
- const emitResult = program.emit();
588
- if (emitResult.diagnostics.length > 0) {
589
- const diagnostics = TS.formatDiagnosticsWithColorAndContext(emitResult.diagnostics, {
590
- getCanonicalFileName: (path) => path,
591
- getCurrentDirectory: () => cwd,
592
- getNewLine: () => "\n"
593
- });
594
- throw new Error(`TypeScript declaration generation failed:
595
- ${diagnostics}`);
596
- }
597
- }
598
- for (const entry of entries) {
599
- if (entry === "umd")
600
- continue;
601
- const jsPath = Path2.join(distSrcDir, `${entry}.js`);
602
- const dtsPath = Path2.join(distSrcDir, `${entry}.d.ts`);
603
- if (await fileExists(jsPath) && await fileExists(dtsPath)) {
604
- const content = await FS2.readFile(jsPath, "utf-8");
605
- if (content.startsWith("#!")) {
606
- const lines = content.split("\n");
607
- const shebang = lines[0];
608
- const rest = lines.slice(1).join("\n");
609
- await FS2.writeFile(jsPath, `${shebang}
610
- /// <reference types="./${entry}.d.ts" />
611
- ${rest}`);
612
- } else {
613
- await FS2.writeFile(jsPath, `/// <reference types="./${entry}.d.ts" />
614
- ${content}`);
615
- }
616
- }
617
- }
618
762
  const autoDiscoveredFiles = [];
619
- console.log(" Generating package.json...");
763
+ console.info(" Generating package.json...");
620
764
  const cleanedPkg = cleanPackageJSON(pkg, mainEntry, options);
621
765
  const exportsResult = generateExports(entries, mainEntry, options, pkg.exports);
622
766
  cleanedPkg.exports = fixExportsForDist(exportsResult.exports);
@@ -626,7 +770,7 @@ ${content}`);
626
770
  console.warn(` - ${staleExport}`);
627
771
  }
628
772
  if (save) {
629
- console.log(" Removing stale exports from root package.json (--save mode)");
773
+ console.info(" Removing stale exports from root package.json (--save mode)");
630
774
  } else {
631
775
  console.warn(" Use --save to remove these from root package.json");
632
776
  }
@@ -639,62 +783,71 @@ ${content}`);
639
783
  }
640
784
  }
641
785
  const fixedDistPkg = fixExportsForDist(cleanedPkg);
642
- await FS2.writeFile(
643
- Path2.join(distDir, "package.json"),
786
+ await FS3.writeFile(
787
+ Path3.join(distDir, "package.json"),
644
788
  JSON.stringify(fixedDistPkg, null, 2) + "\n"
645
789
  );
646
790
  const defaultFilesToCopy = ["README.md", "LICENSE", "CHANGELOG.md"];
647
791
  for (const file of defaultFilesToCopy) {
648
- const srcPath = Path2.join(cwd, file);
792
+ const srcPath = Path3.join(cwd, file);
649
793
  if (await fileExists(srcPath)) {
650
- console.log(` Copying ${file}...`);
651
- await FS2.copyFile(srcPath, Path2.join(distDir, file));
794
+ console.info(` Copying ${file}...`);
795
+ await FS3.copyFile(srcPath, Path3.join(distDir, file));
652
796
  }
653
797
  }
654
798
  const commonFiles = ["README.md", "LICENSE", "CHANGELOG.md", "COPYING", "AUTHORS"];
655
799
  if (pkg.files && Array.isArray(pkg.files)) {
656
800
  for (const commonFile of commonFiles) {
657
- const commonPath = Path2.join(cwd, commonFile);
801
+ const commonPath = Path3.join(cwd, commonFile);
658
802
  if (await fileExists(commonPath) && !pkg.files.includes(commonFile)) {
659
- console.log(` Auto-discovered ${commonFile}, adding to files field...`);
803
+ console.info(` Auto-discovered ${commonFile}, adding to files field...`);
660
804
  pkg.files.push(commonFile);
661
805
  autoDiscoveredFiles.push(commonFile);
662
806
  }
663
807
  }
664
808
  }
665
809
  if (pkg.files && Array.isArray(pkg.files)) {
666
- console.log(" Copying files from package.json files field...");
810
+ console.info(" Copying files from package.json files field...");
667
811
  for (const pattern of pkg.files) {
668
812
  if (typeof pattern === "string" && (pattern.includes("src") || pattern.includes("dist"))) {
669
813
  continue;
670
814
  }
671
815
  if (typeof pattern === "string") {
672
- const srcPath = Path2.join(cwd, pattern);
673
- const destPath = Path2.join(distDir, pattern);
674
- if (await fileExists(srcPath)) {
675
- const stat2 = await FS2.stat(srcPath);
816
+ const validatedSrcPath = validatePath(pattern, cwd);
817
+ const validatedDestPath = validatePath(pattern, distDir);
818
+ if (await fileExists(validatedSrcPath)) {
819
+ const stat2 = await FS3.stat(validatedSrcPath);
820
+ if (stat2.isSymbolicLink()) {
821
+ throw new Error(`Symbolic links are not allowed in files field: ${pattern}`);
822
+ }
676
823
  if (stat2.isDirectory()) {
677
- console.log(` Copying directory ${pattern}/...`);
678
- await FS2.mkdir(Path2.dirname(destPath), { recursive: true });
679
- await FS2.cp(srcPath, destPath, { recursive: true });
824
+ console.info(` Copying directory ${pattern}/...`);
825
+ await FS3.mkdir(Path3.dirname(validatedDestPath), { recursive: true });
826
+ await FS3.cp(validatedSrcPath, validatedDestPath, { recursive: true });
827
+ } else if (stat2.isFile()) {
828
+ console.info(` Copying ${pattern}...`);
829
+ await FS3.mkdir(Path3.dirname(validatedDestPath), { recursive: true });
830
+ await FS3.copyFile(validatedSrcPath, validatedDestPath);
680
831
  } else {
681
- console.log(` Copying ${pattern}...`);
682
- await FS2.mkdir(Path2.dirname(destPath), { recursive: true });
683
- await FS2.copyFile(srcPath, destPath);
832
+ throw new Error(`Unsupported file type for ${pattern}. Only regular files and directories are allowed.`);
684
833
  }
685
834
  } else if (pattern.includes("*")) {
686
835
  const baseDir = pattern.split("*")[0].replace(/\/$/, "");
687
- if (baseDir && await fileExists(Path2.join(cwd, baseDir))) {
688
- console.log(` Copying pattern ${pattern}...`);
689
- const baseSrcPath = Path2.join(cwd, baseDir);
690
- const baseDestPath = Path2.join(distDir, baseDir);
691
- await FS2.mkdir(Path2.dirname(baseDestPath), { recursive: true });
692
- await FS2.cp(baseSrcPath, baseDestPath, { recursive: true });
836
+ if (baseDir) {
837
+ const validatedBaseSrcPath = validatePath(baseDir, cwd);
838
+ const validatedBaseDestPath = validatePath(baseDir, distDir);
839
+ if (await fileExists(validatedBaseSrcPath)) {
840
+ console.info(` Copying pattern ${pattern}...`);
841
+ await FS3.mkdir(Path3.dirname(validatedBaseDestPath), { recursive: true });
842
+ await FS3.cp(validatedBaseSrcPath, validatedBaseDestPath, { recursive: true });
843
+ } else {
844
+ throw new Error(`Pattern base directory not found for "${pattern}". Expected directory: ${validatedBaseSrcPath}`);
845
+ }
693
846
  } else {
694
- throw new Error(`Pattern base directory not found for "${pattern}". Expected directory: ${Path2.join(cwd, baseDir)}`);
847
+ throw new Error(`Invalid pattern "${pattern}". Pattern must have a base directory before the wildcard.`);
695
848
  }
696
849
  } else {
697
- throw new Error(`File specified in files field not found: ${srcPath}. Remove "${pattern}" from package.json files field or create the file.`);
850
+ throw new Error(`File specified in files field not found: ${validatedSrcPath}. Remove "${pattern}" from package.json files field or create the file.`);
698
851
  }
699
852
  } else {
700
853
  throw new Error(`Invalid files field entry: ${JSON.stringify(pattern)}. Files field entries must be strings.`);
@@ -702,7 +855,7 @@ ${content}`);
702
855
  }
703
856
  }
704
857
  if (save) {
705
- console.log(" Updating root package.json...");
858
+ console.info(" Updating root package.json...");
706
859
  const rootPkg2 = { ...pkg };
707
860
  rootPkg2.private = true;
708
861
  if (options.formats.cjs) {
@@ -711,7 +864,7 @@ ${content}`);
711
864
  rootPkg2.module = `./dist/src/${mainEntry}.js`;
712
865
  rootPkg2.types = `./dist/src/${mainEntry}.d.ts`;
713
866
  if (rootPkg2.typings && typeof rootPkg2.typings === "string") {
714
- rootPkg2.typings = rootPkg2.typings.startsWith("./dist/") ? rootPkg2.typings : "./" + Path2.join("dist", rootPkg2.typings);
867
+ rootPkg2.typings = rootPkg2.typings.startsWith("./dist/") ? rootPkg2.typings : "./" + Path3.join("dist", rootPkg2.typings);
715
868
  }
716
869
  const rootExports = {};
717
870
  for (const [key, value] of Object.entries(cleanedPkg.exports)) {
@@ -730,12 +883,20 @@ ${content}`);
730
883
  if (rootPkg2.bin) {
731
884
  if (typeof rootPkg2.bin === "string") {
732
885
  if (!rootPkg2.bin.startsWith("./dist/")) {
733
- rootPkg2.bin = "./" + Path2.join("dist", rootPkg2.bin);
886
+ if (rootPkg2.bin.startsWith("dist/")) {
887
+ rootPkg2.bin = "./" + rootPkg2.bin;
888
+ } else {
889
+ rootPkg2.bin = "./" + Path3.join("dist", rootPkg2.bin);
890
+ }
734
891
  }
735
892
  } else {
736
893
  for (const [name, binPath] of Object.entries(rootPkg2.bin)) {
737
894
  if (typeof binPath === "string" && !binPath.startsWith("./dist/")) {
738
- rootPkg2.bin[name] = "./" + Path2.join("dist", binPath);
895
+ if (binPath.startsWith("dist/")) {
896
+ rootPkg2.bin[name] = "./" + binPath;
897
+ } else {
898
+ rootPkg2.bin[name] = "./" + Path3.join("dist", binPath);
899
+ }
739
900
  }
740
901
  }
741
902
  }
@@ -755,51 +916,52 @@ ${content}`);
755
916
  rootPkg2.files.push("dist/");
756
917
  }
757
918
  }
758
- await FS2.writeFile(pkgPath, JSON.stringify(rootPkg2, null, 2) + "\n");
919
+ await FS3.writeFile(pkgPath, JSON.stringify(rootPkg2, null, 2) + "\n");
759
920
  } else {
760
- console.log(" Skipping root package.json update (use --save to enable)");
921
+ console.info(" Skipping root package.json update (use --save to enable)");
761
922
  }
762
- console.log("\nBuild complete!");
763
- console.log(`
923
+ console.info("\nBuild complete!");
924
+ console.info(`
764
925
  Output: ${distDir}`);
765
- console.log(`
926
+ console.info(`
766
927
  Entries: ${entries.length}`);
767
928
  if (options.formats.cjs) {
768
- console.log(`
929
+ console.info(`
769
930
  Formats: ESM, CJS${options.formats.umd ? ", UMD" : ""}`);
770
931
  } else {
771
- console.log(`
932
+ console.info(`
772
933
  Formats: ESM${options.formats.umd ? ", UMD" : ""}`);
773
934
  }
774
935
  let rootPkg = pkg;
775
936
  if (save) {
776
- rootPkg = JSON.parse(await FS2.readFile(pkgPath, "utf-8"));
937
+ rootPkg = JSON.parse(await FS3.readFile(pkgPath, "utf-8"));
777
938
  }
778
939
  return { distPkg: fixedDistPkg, rootPkg };
779
940
  }
780
- async function publish(cwd, save = true) {
941
+ async function publish(cwd, save = true, extraArgs = []) {
781
942
  await build2(cwd, save);
782
- console.log("\nPublishing to npm...");
783
- const distDir = Path2.join(cwd, "dist");
784
- const distPkgPath = Path2.join(distDir, "package.json");
943
+ console.info("\nPublishing to npm...");
944
+ const distDir = Path3.join(cwd, "dist");
945
+ const distPkgPath = Path3.join(distDir, "package.json");
785
946
  if (!await fileExists(distPkgPath)) {
786
947
  throw new Error("No dist/package.json found. Run 'libuild build' first.");
787
948
  }
788
- const distPkg = JSON.parse(await FS2.readFile(distPkgPath, "utf-8"));
949
+ const distPkg = JSON.parse(await FS3.readFile(distPkgPath, "utf-8"));
789
950
  const publishArgs = ["publish"];
790
951
  if (distPkg.name.startsWith("@")) {
791
952
  publishArgs.push("--access", "public");
792
953
  }
954
+ publishArgs.push(...extraArgs);
793
955
  const proc = (0, import_child_process.spawn)("npm", publishArgs, {
794
956
  cwd: distDir,
795
957
  stdio: "inherit"
796
958
  });
797
- const exitCode = await new Promise((resolve) => {
798
- proc.on("close", resolve);
959
+ const exitCode = await new Promise((resolve3) => {
960
+ proc.on("close", resolve3);
799
961
  });
800
962
  if (exitCode === 0) {
801
- const distPkg2 = JSON.parse(await FS2.readFile(distPkgPath, "utf-8"));
802
- console.log(`
963
+ const distPkg2 = JSON.parse(await FS3.readFile(distPkgPath, "utf-8"));
964
+ console.info(`
803
965
  Published ${distPkg2.name}@${distPkg2.version}!`);
804
966
  } else {
805
967
  throw new Error("npm publish failed");
@@ -811,4 +973,3 @@ Published ${distPkg2.name}@${distPkg2.version}!`);
811
973
  publish,
812
974
  transformSrcToDist
813
975
  });
814
- //# sourceMappingURL=libuild.cjs.map