@kidd-cli/bundler 0.1.3 → 0.2.0
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/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ type AsyncBundlerResult<T> = AsyncResult<T, Error>;
|
|
|
75
75
|
interface BuildOutput {
|
|
76
76
|
readonly outDir: string;
|
|
77
77
|
readonly entryFile: string;
|
|
78
|
+
readonly version: string | undefined;
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
80
81
|
* A single compiled binary for a specific target platform.
|
|
@@ -142,7 +143,9 @@ interface ScanResult {
|
|
|
142
143
|
/**
|
|
143
144
|
* Build a kidd CLI tool using tsdown.
|
|
144
145
|
*
|
|
145
|
-
* Resolves defaults,
|
|
146
|
+
* Resolves defaults, reads the project version from package.json, maps the
|
|
147
|
+
* config to tsdown's InlineConfig (injecting `__KIDD_VERSION__`), and invokes
|
|
148
|
+
* the build.
|
|
146
149
|
*
|
|
147
150
|
* @param params - The build parameters including config and working directory.
|
|
148
151
|
* @returns A result tuple with build output on success or an Error on failure.
|
|
@@ -219,18 +222,22 @@ declare function generateAutoloaderParts(params: GenerateStaticAutoloaderParams)
|
|
|
219
222
|
/**
|
|
220
223
|
* Map a resolved bundler config to a tsdown InlineConfig for production builds.
|
|
221
224
|
*
|
|
222
|
-
* @param
|
|
225
|
+
* @param params - The resolved config and optional version for compile-time injection.
|
|
223
226
|
* @returns A tsdown InlineConfig ready for `build()`.
|
|
224
227
|
*/
|
|
225
|
-
declare function mapToBuildConfig(
|
|
228
|
+
declare function mapToBuildConfig(params: {
|
|
229
|
+
readonly config: ResolvedBundlerConfig;
|
|
230
|
+
readonly version?: string;
|
|
231
|
+
}): InlineConfig;
|
|
226
232
|
/**
|
|
227
233
|
* Map a resolved bundler config to a tsdown InlineConfig for watch mode.
|
|
228
234
|
*
|
|
229
|
-
* @param params - The resolved config and optional success callback.
|
|
235
|
+
* @param params - The resolved config, optional version, and optional success callback.
|
|
230
236
|
* @returns A tsdown InlineConfig with `watch: true`.
|
|
231
237
|
*/
|
|
232
238
|
declare function mapToWatchConfig(params: {
|
|
233
239
|
readonly config: ResolvedBundlerConfig;
|
|
240
|
+
readonly version?: string;
|
|
234
241
|
readonly onSuccess?: () => void | Promise<void>;
|
|
235
242
|
}): InlineConfig;
|
|
236
243
|
//#endregion
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/autoload-plugin.ts","../src/types.ts","../src/build.ts","../src/compile.ts","../src/generate-autoloader.ts","../src/map-config.ts","../src/resolve-config.ts","../src/scan-commands.ts","../src/watch.ts"],"mappings":";;;;;;;;UAcU,0BAAA;EAAA,SACC,WAAA;EAAA,SACA,aAAA;AAAA;;;AAsBX;;;;;;;;;;;;;AC5BA;;;;iBD4BgB,oBAAA,CAAqB,MAAA,EAAQ,0BAAA,GAA6B,QAAA,CAAS,MAAA;;;;;;UC5BlE,oBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAAA,SACA,SAAA;EAAA,SACA,QAAA;AAAA;;;;UAMM,sBAAA;EAAA,SACN,OAAA,WAAkB,aAAA;EAAA,SAClB,IAAA;AAAA;;;;UAMM,qBAAA;EAAA,SACN,KAAA;EAAA,SACA,QAAA;EAAA,SACA,WAAA;EAAA,SACA,aAAA;EAAA,SACA,KAAA,EAAO,oBAAA;EAAA,SACP,OAAA,EAAS,sBAAA;EAAA,SACT,OAAA;EAAA,SACA,GAAA;AAAA;;;AAhBX;KA0BY,aAAA,MAAmB,MAAA,CAAO,CAAA,EAAG,KAAA;;;;KAK7B,kBAAA,MAAwB,WAAA,CAAY,CAAA,EAAG,KAAA;;;;UASlC,WAAA;EAAA,SACN,MAAA;EAAA,SACA,SAAA;AAAA;;;;UAMM,cAAA;EAAA,SACN,MAAA,EAAQ,aAAA;EAAA,SACR,KAAA;EAAA,SACA,IAAA;AAAA;;;;UAMM,aAAA;EAAA,SACN,QAAA,WAAmB,cAAA;AAAA;;;;UAUb,WAAA;EAAA,SACN,MAAA,EAAQ,UAAA;EAAA,SACR,GAAA;AAAA;;;;UAMM,WAAA;EAAA,SACN,MAAA,EAAQ,UAAA;EAAA,SACR,GAAA;EAAA,SACA,SAAA,gBAAyB,OAAA;AAAA;;;;UAMnB,aAAA;EAAA,SACN,MAAA,EAAQ,UAAA;EAAA,SACR,GAAA;EAAA,SACA,aAAA,IAAiB,MAAA,EAAQ,aAAA,YAAyB,OAAA;EAAA,SAClD,gBAAA,IAAoB,MAAA,EAAQ,aAAA,YAAyB,OAAA;AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/autoload-plugin.ts","../src/types.ts","../src/build.ts","../src/compile.ts","../src/generate-autoloader.ts","../src/map-config.ts","../src/resolve-config.ts","../src/scan-commands.ts","../src/watch.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import { readdir } from "node:fs/promises";
|
|
|
3
3
|
import { basename, extname, join, resolve } from "node:path";
|
|
4
4
|
import { err, ok } from "@kidd-cli/utils/fp";
|
|
5
5
|
import { build as build$1 } from "tsdown";
|
|
6
|
+
import { match } from "ts-pattern";
|
|
7
|
+
import { readManifest } from "@kidd-cli/utils/manifest";
|
|
6
8
|
import { existsSync, readdirSync, unlinkSync } from "node:fs";
|
|
7
9
|
import { execFile } from "node:child_process";
|
|
8
10
|
//#region src/generate-autoloader.ts
|
|
@@ -452,46 +454,51 @@ const NODE_BUILTINS = [...builtinModules, ...builtinModules.map((m) => `node:${m
|
|
|
452
454
|
/**
|
|
453
455
|
* Map a resolved bundler config to a tsdown InlineConfig for production builds.
|
|
454
456
|
*
|
|
455
|
-
* @param
|
|
457
|
+
* @param params - The resolved config and optional version for compile-time injection.
|
|
456
458
|
* @returns A tsdown InlineConfig ready for `build()`.
|
|
457
459
|
*/
|
|
458
|
-
function mapToBuildConfig(
|
|
460
|
+
function mapToBuildConfig(params) {
|
|
459
461
|
return {
|
|
460
462
|
banner: SHEBANG,
|
|
461
463
|
clean: true,
|
|
462
464
|
config: false,
|
|
463
|
-
cwd: config.cwd,
|
|
465
|
+
cwd: params.config.cwd,
|
|
466
|
+
define: buildDefine(params.version),
|
|
464
467
|
deps: {
|
|
465
468
|
alwaysBundle: ALWAYS_BUNDLE,
|
|
466
|
-
neverBundle: buildExternals(config.build.external)
|
|
469
|
+
neverBundle: buildExternals(params.config.build.external)
|
|
467
470
|
},
|
|
468
471
|
dts: false,
|
|
469
|
-
entry: { index: config.entry },
|
|
472
|
+
entry: { index: params.config.entry },
|
|
470
473
|
format: "esm",
|
|
471
474
|
inputOptions: { resolve: { mainFields: ["module", "main"] } },
|
|
472
|
-
logLevel: "
|
|
473
|
-
minify: config.build.minify,
|
|
474
|
-
outDir: config.buildOutDir,
|
|
475
|
+
logLevel: "silent",
|
|
476
|
+
minify: params.config.build.minify,
|
|
477
|
+
outDir: params.config.buildOutDir,
|
|
475
478
|
outputOptions: { codeSplitting: false },
|
|
476
479
|
platform: "node",
|
|
477
480
|
plugins: [createAutoloadPlugin({
|
|
478
|
-
commandsDir: config.commands,
|
|
481
|
+
commandsDir: params.config.commands,
|
|
479
482
|
tagModulePath: resolveTagModulePath()
|
|
480
483
|
})],
|
|
481
|
-
sourcemap: config.build.sourcemap,
|
|
482
|
-
target: config.build.target,
|
|
484
|
+
sourcemap: params.config.build.sourcemap,
|
|
485
|
+
target: params.config.build.target,
|
|
483
486
|
treeshake: true
|
|
484
487
|
};
|
|
485
488
|
}
|
|
486
489
|
/**
|
|
487
490
|
* Map a resolved bundler config to a tsdown InlineConfig for watch mode.
|
|
488
491
|
*
|
|
489
|
-
* @param params - The resolved config and optional success callback.
|
|
492
|
+
* @param params - The resolved config, optional version, and optional success callback.
|
|
490
493
|
* @returns A tsdown InlineConfig with `watch: true`.
|
|
491
494
|
*/
|
|
492
495
|
function mapToWatchConfig(params) {
|
|
493
496
|
return {
|
|
494
|
-
...mapToBuildConfig(
|
|
497
|
+
...mapToBuildConfig({
|
|
498
|
+
config: params.config,
|
|
499
|
+
version: params.version
|
|
500
|
+
}),
|
|
501
|
+
logLevel: "error",
|
|
495
502
|
onSuccess: params.onSuccess,
|
|
496
503
|
watch: true
|
|
497
504
|
};
|
|
@@ -507,6 +514,19 @@ function buildExternals(userExternals) {
|
|
|
507
514
|
return [...NODE_BUILTINS, ...userExternals];
|
|
508
515
|
}
|
|
509
516
|
/**
|
|
517
|
+
* Build the `define` map for compile-time constants.
|
|
518
|
+
*
|
|
519
|
+
* Injects `__KIDD_VERSION__` when a version string is available so that
|
|
520
|
+
* the runtime can auto-detect the CLI version without reading package.json.
|
|
521
|
+
*
|
|
522
|
+
* @private
|
|
523
|
+
* @param version - The version string from package.json, or undefined.
|
|
524
|
+
* @returns A define map for tsdown/rolldown.
|
|
525
|
+
*/
|
|
526
|
+
function buildDefine(version) {
|
|
527
|
+
return match(version).with(void 0, () => ({})).otherwise((resolvedVersion) => ({ __KIDD_VERSION__: JSON.stringify(resolvedVersion) }));
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
510
530
|
* Resolve the absolute file path to the `@kidd-cli/utils/tag` module.
|
|
511
531
|
*
|
|
512
532
|
* The static autoloader virtual module imports `withTag` via this path.
|
|
@@ -521,6 +541,23 @@ function resolveTagModulePath() {
|
|
|
521
541
|
return createRequire(import.meta.url).resolve("@kidd-cli/utils/tag");
|
|
522
542
|
}
|
|
523
543
|
//#endregion
|
|
544
|
+
//#region src/read-version.ts
|
|
545
|
+
/**
|
|
546
|
+
* Read the version string from a project's package.json.
|
|
547
|
+
*
|
|
548
|
+
* Uses `readManifest` to parse the package.json at the given directory and
|
|
549
|
+
* extracts the `version` field. Returns `undefined` when the manifest has no
|
|
550
|
+
* version set.
|
|
551
|
+
*
|
|
552
|
+
* @param cwd - Directory containing the package.json.
|
|
553
|
+
* @returns A result tuple with the version string (or undefined) on success, or an Error on failure.
|
|
554
|
+
*/
|
|
555
|
+
async function readVersion(cwd) {
|
|
556
|
+
const [manifestError, manifest] = await readManifest(cwd);
|
|
557
|
+
if (manifestError) return [/* @__PURE__ */ new Error(`Failed to read version: ${manifestError.message}`), null];
|
|
558
|
+
return [null, manifest.version];
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
524
561
|
//#region src/resolve-config.ts
|
|
525
562
|
/**
|
|
526
563
|
* Known entry file names produced by tsdown for ESM builds, in preference order.
|
|
@@ -594,14 +631,22 @@ function detectBuildEntry(outDir) {
|
|
|
594
631
|
/**
|
|
595
632
|
* Build a kidd CLI tool using tsdown.
|
|
596
633
|
*
|
|
597
|
-
* Resolves defaults,
|
|
634
|
+
* Resolves defaults, reads the project version from package.json, maps the
|
|
635
|
+
* config to tsdown's InlineConfig (injecting `__KIDD_VERSION__`), and invokes
|
|
636
|
+
* the build.
|
|
598
637
|
*
|
|
599
638
|
* @param params - The build parameters including config and working directory.
|
|
600
639
|
* @returns A result tuple with build output on success or an Error on failure.
|
|
601
640
|
*/
|
|
602
641
|
async function build(params) {
|
|
603
642
|
const resolved = resolveConfig(params);
|
|
604
|
-
const
|
|
643
|
+
const [versionError, versionResult] = await readVersion(params.cwd);
|
|
644
|
+
if (versionError) console.warn("[kidd-bundler] could not read version from package.json:", versionError.message);
|
|
645
|
+
const version = versionResult ?? void 0;
|
|
646
|
+
const inlineConfig = mapToBuildConfig({
|
|
647
|
+
config: resolved,
|
|
648
|
+
version
|
|
649
|
+
});
|
|
605
650
|
try {
|
|
606
651
|
await build$1(inlineConfig);
|
|
607
652
|
} catch (error) {
|
|
@@ -612,7 +657,8 @@ async function build(params) {
|
|
|
612
657
|
if (!entryFile) return err(/* @__PURE__ */ new Error(`build produced no entry file in ${resolved.buildOutDir}`));
|
|
613
658
|
return ok({
|
|
614
659
|
entryFile,
|
|
615
|
-
outDir: resolved.buildOutDir
|
|
660
|
+
outDir: resolved.buildOutDir,
|
|
661
|
+
version
|
|
616
662
|
});
|
|
617
663
|
}
|
|
618
664
|
//#endregion
|
|
@@ -793,9 +839,14 @@ function cleanBunBuildArtifacts(cwd) {
|
|
|
793
839
|
* @returns A result tuple with void on success or an Error on failure.
|
|
794
840
|
*/
|
|
795
841
|
async function watch(params) {
|
|
842
|
+
const resolved = resolveConfig(params);
|
|
843
|
+
const [versionError, versionResult] = await readVersion(params.cwd);
|
|
844
|
+
if (versionError) console.warn("[kidd-bundler] could not read version from package.json:", versionError.message);
|
|
845
|
+
const version = versionResult ?? void 0;
|
|
796
846
|
const watchConfig = mapToWatchConfig({
|
|
797
|
-
config:
|
|
798
|
-
onSuccess: params.onSuccess
|
|
847
|
+
config: resolved,
|
|
848
|
+
onSuccess: params.onSuccess,
|
|
849
|
+
version
|
|
799
850
|
});
|
|
800
851
|
try {
|
|
801
852
|
await build$1(watchConfig);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["tsdownBuild","tsdownBuild"],"sources":["../src/generate-autoloader.ts","../src/scan-commands.ts","../src/autoload-plugin.ts","../src/constants.ts","../src/map-config.ts","../src/resolve-config.ts","../src/build.ts","../src/compile.ts","../src/watch.ts"],"sourcesContent":["import type { ScanResult, ScannedDir, ScannedFile } from './types.js'\n\n/**\n * Parameters for generating a static autoloader module.\n */\ninterface GenerateStaticAutoloaderParams {\n readonly scan: ScanResult\n readonly tagModulePath: string\n}\n\n/**\n * The two parts of a static autoloader transform: import statements to\n * prepend and the replacement code for the autoloader region.\n */\nexport interface StaticAutoloaderParts {\n readonly imports: string\n readonly region: string\n}\n\n/**\n * Generate JavaScript source code for a static autoloader virtual module.\n *\n * The generated module statically imports every discovered command file and\n * exports an `autoload()` function that returns the pre-built CommandMap.\n * Directory commands that merge a parent handler with subcommands are re-tagged\n * via `withTag` because the TAG symbol is non-enumerable and lost on spread.\n *\n * @param params - The scan result and path to the tag utility module.\n * @returns JavaScript source code for the static autoloader.\n */\nexport function generateStaticAutoloader(params: GenerateStaticAutoloaderParams): string {\n const imports = collectImports(params.scan)\n const importLines = buildImportStatements(imports, params.tagModulePath)\n const commandsObject = buildCommandsObject(params.scan)\n\n return [\n ...importLines,\n '',\n `const commands = ${commandsObject}`,\n '',\n 'export async function autoload() {',\n ' return commands',\n '}',\n '',\n ].join('\\n')\n}\n\n/**\n * Generate the two parts needed to transform kidd's bundled dist.\n *\n * Returns an empty imports string (no prepended imports needed) and a\n * replacement autoloader region that uses dynamic `import()` calls inside\n * the async `autoload()` function. This avoids circular dependency issues:\n * command files import `command` from `@kidd-cli/core`, so static imports would be\n * hoisted above kidd's own initialization code, causing `TAG` to be\n * accessed before initialization.\n *\n * By deferring to dynamic imports, kidd fully initializes first, then\n * command files are loaded when `autoload()` is called at CLI startup.\n *\n * @param params - The scan result and path to the tag utility module.\n * @returns Import statements (empty) and the replacement autoloader region.\n */\nexport function generateAutoloaderParts(\n params: GenerateStaticAutoloaderParams\n): StaticAutoloaderParts {\n const imports = collectImports(params.scan)\n\n if (imports.length === 0) {\n return {\n imports: '',\n region: buildEmptyAutoloaderRegion(),\n }\n }\n\n const commandsObject = buildCommandsObject(params.scan)\n const region = buildDynamicAutoloaderRegion(imports, commandsObject)\n\n return { imports: '', region }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * A collected import entry with its identifier and absolute file path.\n *\n * @private\n */\ninterface ImportEntry {\n readonly identifier: string\n readonly filePath: string\n}\n\n/**\n * Collect all import entries from a scan result.\n *\n * @private\n * @param scan - The scan result to collect imports from.\n * @returns A flat array of all import entries.\n */\nfunction collectImports(scan: ScanResult): readonly ImportEntry[] {\n return [\n ...scan.files.map((file) => fileToImport(file, [])),\n ...scan.dirs.flatMap((dir) => collectDirImports(dir, [])),\n ]\n}\n\n/**\n * Recursively collect import entries from a scanned directory.\n *\n * @private\n * @param dir - The scanned directory.\n * @param parentPath - The path segments leading to this directory.\n * @returns A flat array of import entries for the directory and its children.\n */\nfunction collectDirImports(dir: ScannedDir, parentPath: readonly string[]): readonly ImportEntry[] {\n const currentPath = [...parentPath, dir.name]\n const indexImport: readonly ImportEntry[] = buildIndexImport(dir.index, currentPath)\n\n return [\n ...indexImport,\n ...dir.files.map((file) => fileToImport(file, currentPath)),\n ...dir.dirs.flatMap((sub) => collectDirImports(sub, currentPath)),\n ]\n}\n\n/**\n * Create an import entry for a leaf command file.\n *\n * @private\n * @param file - The scanned file.\n * @param parentPath - The path segments leading to the file's parent directory.\n * @returns An import entry with a generated identifier.\n */\nfunction fileToImport(file: ScannedFile, parentPath: readonly string[]): ImportEntry {\n return {\n filePath: file.filePath,\n identifier: toIdentifier([...parentPath, file.name]),\n }\n}\n\n/**\n * Convert a path segment array to a valid JavaScript identifier.\n *\n * Joins segments with underscores and prefixes with `_`.\n * Example: `['deploy', 'preview']` becomes `_deploy_preview`.\n *\n * @private\n * @param segments - The path segments to convert.\n * @returns A valid JavaScript identifier string.\n */\nfunction toIdentifier(segments: readonly string[]): string {\n return `_${segments.map((s) => s.replaceAll('-', '$')).join('_')}`\n}\n\n/**\n * Build the array of import statement lines.\n *\n * @private\n * @param imports - All collected import entries.\n * @param tagModulePath - Absolute path to the tag utility module.\n * @returns An array of import statement strings.\n */\nfunction buildImportStatements(\n imports: readonly ImportEntry[],\n tagModulePath: string\n): readonly string[] {\n const tagLine = buildTagImportLine(imports, tagModulePath)\n\n const importLines = imports.map((entry) => `import ${entry.identifier} from '${entry.filePath}'`)\n\n return [...tagLine, '', ...importLines]\n}\n\n/**\n * Build the JavaScript object literal string for the top-level commands map.\n *\n * @private\n * @param scan - The scan result.\n * @returns A string representation of the commands object literal.\n */\nfunction buildCommandsObject(scan: ScanResult): string {\n const entries = [\n ...scan.files.map((file) => buildFileEntry(file, [])),\n ...scan.dirs.map((dir) => buildDirEntry(dir, [])),\n ]\n\n return formatObject(entries)\n}\n\n/**\n * Build an object entry string for a leaf command file.\n *\n * @private\n * @param file - The scanned file.\n * @param parentPath - Path segments to the file's parent.\n * @returns A string like `'status': _status`.\n */\nfunction buildFileEntry(file: ScannedFile, parentPath: readonly string[]): string {\n const identifier = toIdentifier([...parentPath, file.name])\n return `'${file.name}': ${identifier}`\n}\n\n/**\n * Build an object entry string for a directory command (possibly with subcommands).\n *\n * @private\n * @param dir - The scanned directory.\n * @param parentPath - Path segments to the directory's parent.\n * @returns A string representing the directory command with withTag wrapping.\n */\nfunction buildDirEntry(dir: ScannedDir, parentPath: readonly string[]): string {\n const currentPath = [...parentPath, dir.name]\n const subEntries = [\n ...dir.files.map((file) => buildFileEntry(file, currentPath)),\n ...dir.dirs.map((sub) => buildDirEntry(sub, currentPath)),\n ]\n const commandsObj = formatObject(subEntries)\n\n if (dir.index) {\n const indexIdentifier = toIdentifier(currentPath)\n\n return `'${dir.name}': withTag({ ...${indexIdentifier}, commands: ${commandsObj} }, 'Command')`\n }\n\n return `'${dir.name}': withTag({ commands: ${commandsObj} }, 'Command')`\n}\n\n/**\n * Build the import entry for an index file, if present.\n *\n * @private\n * @param index - The absolute path to the index file, or undefined.\n * @param currentPath - The current path segments for identifier generation.\n * @returns An array with zero or one import entries.\n */\nfunction buildIndexImport(\n index: string | undefined,\n currentPath: readonly string[]\n): readonly ImportEntry[] {\n if (!index) {\n return []\n }\n return [{ filePath: index, identifier: toIdentifier(currentPath) }]\n}\n\n/**\n * Build the tag import line if any imports exist.\n *\n * @private\n * @param imports - The collected import entries.\n * @param tagModulePath - The absolute path to the tag module.\n * @returns An array with zero or one import statement strings.\n */\nfunction buildTagImportLine(\n imports: readonly ImportEntry[],\n tagModulePath: string\n): readonly string[] {\n if (imports.length === 0) {\n return []\n }\n return [`import { withTag } from '${tagModulePath}'`]\n}\n\n/**\n * Build the autoloader region for an empty scan result.\n *\n * @private\n * @returns A region string with an autoloader that returns an empty object.\n */\nfunction buildEmptyAutoloaderRegion(): string {\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ' return {}',\n '}',\n '//#endregion',\n ].join('\\n')\n}\n\n/**\n * Build the autoloader region using dynamic `import()` calls.\n *\n * Uses `Promise.all` with array destructuring to load all command files\n * in parallel. The dynamic imports defer execution until `autoload()` is\n * called, avoiding circular dependency issues with kidd's own initialization.\n *\n * @private\n * @param imports - The collected import entries.\n * @param commandsObject - The commands object literal string.\n * @returns A region string with the full dynamic autoloader.\n */\nfunction buildDynamicAutoloaderRegion(\n imports: readonly ImportEntry[],\n commandsObject: string\n): string {\n const destructuring = imports.map((entry) => ` { default: ${entry.identifier} },`).join('\\n')\n\n const importCalls = imports.map((entry) => ` import('${entry.filePath}'),`).join('\\n')\n\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ' const [',\n destructuring,\n ' ] = await Promise.all([',\n importCalls,\n ' ])',\n ` return ${commandsObject}`,\n '}',\n '//#endregion',\n ].join('\\n')\n}\n\n/**\n * Format an array of key-value strings as a JavaScript object literal.\n *\n * @private\n * @param entries - The key-value pair strings.\n * @returns A formatted object literal string.\n */\nfunction formatObject(entries: readonly string[]): string {\n if (entries.length === 0) {\n return '{}'\n }\n\n const body = entries.map((entry) => ` ${entry},`).join('\\n')\n return `{\\n${body}\\n}`\n}\n","import type { Dirent } from 'node:fs'\nimport { readdir } from 'node:fs/promises'\nimport { basename, extname, join } from 'node:path'\n\nimport type { ScanResult, ScannedDir, ScannedFile } from './types.js'\n\nconst VALID_EXTENSIONS = new Set(['.ts', '.js', '.mjs'])\nconst INDEX_NAME = 'index'\n\n/**\n * Scan a commands directory and produce a tree structure for static code generation.\n *\n * Mirrors the runtime autoloader's rules: valid extensions are `.ts`, `.js`, `.mjs`;\n * files and directories starting with `_` or `.` are skipped; `index` files in\n * subdirectories become parent command handlers.\n *\n * @param dir - Absolute path to the commands directory.\n * @returns A tree of scanned files and directories.\n */\nexport async function scanCommandsDir(dir: string): Promise<ScanResult> {\n const entries = await readdir(dir, { withFileTypes: true })\n\n const files = entries.filter(isCommandFile).map((entry) => toScannedFile(dir, entry))\n\n const dirs = await Promise.all(\n entries.filter(isCommandDir).map((entry) => scanSubDir(join(dir, entry.name)))\n )\n\n return { dirs, files }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively scan a subdirectory into a ScannedDir.\n *\n * @private\n * @param dir - Absolute path to the subdirectory.\n * @returns A ScannedDir representing the directory and its contents.\n */\nasync function scanSubDir(dir: string): Promise<ScannedDir> {\n const name = basename(dir)\n const entries = await readdir(dir, { withFileTypes: true })\n const indexEntry = findIndexEntry(entries)\n\n const files = entries.filter(isCommandFile).map((entry) => toScannedFile(dir, entry))\n\n const dirs = await Promise.all(\n entries.filter(isCommandDir).map((entry) => scanSubDir(join(dir, entry.name)))\n )\n\n return {\n dirs,\n files,\n index: resolveIndexPath(dir, indexEntry),\n name,\n }\n}\n\n/**\n * Convert a directory entry into a ScannedFile.\n *\n * @private\n * @param dir - Parent directory absolute path.\n * @param entry - The directory entry for the file.\n * @returns A ScannedFile with name and absolute file path.\n */\nfunction toScannedFile(dir: string, entry: Dirent): ScannedFile {\n return {\n filePath: join(dir, entry.name),\n name: basename(entry.name, extname(entry.name)),\n }\n}\n\n/**\n * Find the index file entry among a list of directory entries.\n *\n * @private\n * @param entries - The directory entries to search.\n * @returns The Dirent for the index file, or undefined.\n */\nfunction findIndexEntry(entries: readonly Dirent[]): Dirent | undefined {\n return entries.find(\n (entry) =>\n entry.isFile() &&\n VALID_EXTENSIONS.has(extname(entry.name)) &&\n basename(entry.name, extname(entry.name)) === INDEX_NAME\n )\n}\n\n/**\n * Predicate: entry is a valid command file (not index, not hidden/private).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a scannable command file.\n */\nfunction isCommandFile(entry: Dirent): boolean {\n if (!entry.isFile()) {\n return false\n }\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) {\n return false\n }\n if (!VALID_EXTENSIONS.has(extname(entry.name))) {\n return false\n }\n return basename(entry.name, extname(entry.name)) !== INDEX_NAME\n}\n\n/**\n * Predicate: entry is a scannable command directory (not hidden/private).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a scannable command directory.\n */\nfunction isCommandDir(entry: Dirent): boolean {\n if (!entry.isDirectory()) {\n return false\n }\n return !entry.name.startsWith('_') && !entry.name.startsWith('.')\n}\n\n/**\n * Resolve the absolute path to an index file entry, or undefined.\n *\n * @private\n * @param dir - The parent directory absolute path.\n * @param entry - The index file Dirent, or undefined.\n * @returns The absolute path to the index file, or undefined.\n */\nfunction resolveIndexPath(dir: string, entry: Dirent | undefined): string | undefined {\n if (!entry) {\n return undefined\n }\n return join(dir, entry.name)\n}\n","import type { Rolldown } from 'tsdown'\n\nimport { generateStaticAutoloader } from './generate-autoloader.js'\nimport { scanCommandsDir } from './scan-commands.js'\n\nconst VIRTUAL_MODULE_ID = 'virtual:kidd-static-commands'\nconst RESOLVED_VIRTUAL_ID = `\\0${VIRTUAL_MODULE_ID}`\n\nconst AUTOLOADER_REGION_START = '//#region src/autoloader.ts'\nconst AUTOLOADER_REGION_END = '//#endregion'\n\n/**\n * Parameters for creating the autoload plugin.\n */\ninterface CreateAutoloadPluginParams {\n readonly commandsDir: string\n readonly tagModulePath: string\n}\n\n/**\n * Create a rolldown plugin that replaces the runtime autoloader with a static version.\n *\n * Uses a three-hook approach to break the circular dependency between kidd's\n * dist and user command files (which `import { command } from '@kidd-cli/core'`):\n *\n * 1. `transform` — detects kidd's pre-bundled dist and replaces the autoloader\n * region with a dynamic `import()` to a virtual module\n * 2. `resolveId` — resolves the virtual module identifier\n * 3. `load` — scans the commands directory and generates a static autoloader\n * module with all command imports pre-resolved\n *\n * The dynamic import ensures command files execute after kidd's code is fully\n * initialized, avoiding `ReferenceError` from accessing `TAG` before its\n * declaration.\n *\n * @param params - The commands directory and tag module path.\n * @returns A rolldown plugin for static autoloading.\n */\nexport function createAutoloadPlugin(params: CreateAutoloadPluginParams): Rolldown.Plugin {\n return {\n async load(id) {\n if (id !== RESOLVED_VIRTUAL_ID) {\n return null\n }\n\n const scan = await scanCommandsDir(params.commandsDir)\n\n return generateStaticAutoloader({\n scan,\n tagModulePath: params.tagModulePath,\n })\n },\n name: 'kidd-static-autoloader',\n resolveId(source) {\n if (source === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n transform(code, _id) {\n const regionStart = code.indexOf(AUTOLOADER_REGION_START)\n if (regionStart === -1) {\n return null\n }\n\n const regionEnd = code.indexOf(AUTOLOADER_REGION_END, regionStart)\n if (regionEnd === -1) {\n return null\n }\n\n const before = code.slice(0, regionStart)\n const after = code.slice(regionEnd + AUTOLOADER_REGION_END.length)\n const staticRegion = buildStaticRegion()\n\n return `${before}${staticRegion}${after}`\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Build the replacement autoloader region that delegates to the virtual module.\n *\n * @private\n * @returns The replacement region string with dynamic import.\n */\nfunction buildStaticRegion(): string {\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ` const mod = await import('${VIRTUAL_MODULE_ID}')`,\n ' return mod.autoload()',\n '}',\n '//#endregion',\n ].join('\\n')\n}\n","import { builtinModules } from 'node:module'\n\nimport type { CompileTarget } from '@kidd-cli/config'\n\n/**\n * Shebang line prepended to CLI entry files.\n */\nexport const SHEBANG = '#!/usr/bin/env node\\n'\n\n/**\n * Default entry point for the CLI source.\n */\nexport const DEFAULT_ENTRY = './src/index.ts'\n\n/**\n * Default directory for CLI commands.\n */\nexport const DEFAULT_COMMANDS = './commands'\n\n/**\n * Default build output directory.\n */\nexport const DEFAULT_OUT_DIR = './dist'\n\n/**\n * Default Node.js target version for builds.\n */\nexport const DEFAULT_TARGET = 'node18'\n\n/**\n * Default minification setting.\n */\nexport const DEFAULT_MINIFY = false\n\n/**\n * Default source map generation setting.\n */\nexport const DEFAULT_SOURCEMAP = true\n\n/**\n * Default binary name for compiled SEA output.\n */\nexport const DEFAULT_BINARY_NAME = 'cli'\n\n/**\n * Default compile targets when none are explicitly configured.\n *\n * Covers Linux servers/CI, modern and Intel Macs, and Windows — roughly 95%\n * of developer environments.\n */\nexport const DEFAULT_COMPILE_TARGETS: readonly CompileTarget[] = [\n 'darwin-arm64',\n 'darwin-x64',\n 'linux-x64',\n 'windows-x64',\n]\n\n/**\n * Packages that must always be bundled into the output.\n *\n * The `@kidd-cli/core` framework and its internal `@kidd-cli/*` packages must be inlined\n * so the autoload plugin can intercept and replace the runtime autoloader\n * with a static version for compiled binaries.\n */\nexport const ALWAYS_BUNDLE: RegExp[] = [/^@?kidd/]\n\n/**\n * Node.js builtin modules in both bare and `node:` prefixed forms.\n */\nexport const NODE_BUILTINS: readonly string[] = [\n ...builtinModules,\n ...builtinModules.map((m) => `node:${m}`),\n]\n","import { createRequire } from 'node:module'\n\nimport type { InlineConfig } from 'tsdown'\n\nimport { createAutoloadPlugin } from './autoload-plugin.js'\nimport { ALWAYS_BUNDLE, NODE_BUILTINS, SHEBANG } from './constants.js'\nimport type { ResolvedBundlerConfig } from './types.js'\n\n/**\n * Map a resolved bundler config to a tsdown InlineConfig for production builds.\n *\n * @param config - The fully resolved bundler config.\n * @returns A tsdown InlineConfig ready for `build()`.\n */\nexport function mapToBuildConfig(config: ResolvedBundlerConfig): InlineConfig {\n return {\n banner: SHEBANG,\n clean: true,\n config: false,\n cwd: config.cwd,\n deps: {\n alwaysBundle: ALWAYS_BUNDLE,\n neverBundle: buildExternals(config.build.external),\n },\n dts: false,\n entry: { index: config.entry },\n format: 'esm',\n inputOptions: {\n resolve: {\n mainFields: ['module', 'main'],\n },\n },\n logLevel: 'info',\n minify: config.build.minify,\n outDir: config.buildOutDir,\n outputOptions: {\n codeSplitting: false,\n },\n platform: 'node',\n plugins: [\n createAutoloadPlugin({\n commandsDir: config.commands,\n tagModulePath: resolveTagModulePath(),\n }),\n ],\n sourcemap: config.build.sourcemap,\n target: config.build.target,\n treeshake: true,\n }\n}\n\n/**\n * Map a resolved bundler config to a tsdown InlineConfig for watch mode.\n *\n * @param params - The resolved config and optional success callback.\n * @returns A tsdown InlineConfig with `watch: true`.\n */\nexport function mapToWatchConfig(params: {\n readonly config: ResolvedBundlerConfig\n readonly onSuccess?: () => void | Promise<void>\n}): InlineConfig {\n const buildConfig = mapToBuildConfig(params.config)\n\n return {\n ...buildConfig,\n onSuccess: params.onSuccess,\n watch: true,\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Combine Node.js builtins with user-specified externals.\n *\n * @private\n * @param userExternals - Additional packages to mark as external.\n * @returns Combined array of externals for tsdown's `deps.neverBundle`.\n */\nfunction buildExternals(userExternals: readonly string[]): (string | RegExp)[] {\n return [...NODE_BUILTINS, ...userExternals]\n}\n\n/**\n * Resolve the absolute file path to the `@kidd-cli/utils/tag` module.\n *\n * The static autoloader virtual module imports `withTag` via this path.\n * Using an absolute path ensures rolldown can resolve the import from\n * inside the virtual module without relying on tsdown's `alwaysBundle`\n * heuristic, which virtual modules may bypass.\n *\n * @private\n * @returns The absolute file path to the tag module.\n */\nfunction resolveTagModulePath(): string {\n const require = createRequire(import.meta.url)\n return require.resolve('@kidd-cli/utils/tag')\n}\n","import { existsSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport type { CompileOptions, KiddConfig } from '@kidd-cli/config'\n\nimport {\n DEFAULT_BINARY_NAME,\n DEFAULT_COMMANDS,\n DEFAULT_ENTRY,\n DEFAULT_MINIFY,\n DEFAULT_OUT_DIR,\n DEFAULT_SOURCEMAP,\n DEFAULT_TARGET,\n} from './constants.js'\nimport type { ResolvedBundlerConfig } from './types.js'\n\n/**\n * Known entry file names produced by tsdown for ESM builds, in preference order.\n */\nconst ENTRY_CANDIDATES = ['index.mjs', 'index.js'] as const\n\n/**\n * Normalize the `compile` config field from `boolean | CompileOptions | undefined` to `CompileOptions`.\n *\n * - `true` → `{}` (compile with defaults)\n * - `false` / `undefined` → `{}` (no explicit options, caller decides whether to compile)\n * - object → pass through\n *\n * @param value - The raw compile config value.\n * @returns A normalized CompileOptions object.\n */\nexport function normalizeCompileOptions(\n value: boolean | CompileOptions | undefined\n): CompileOptions {\n if (typeof value === 'object') {\n return value\n }\n\n return {}\n}\n\n/**\n * Fill defaults and resolve relative paths against `cwd`.\n *\n * This is a pure function — the incoming config is already validated by `@kidd-cli/config`.\n * It only fills missing optional fields with defaults and resolves paths to absolute.\n *\n * @param params - The raw config and working directory.\n * @returns A fully resolved bundler configuration.\n */\nexport function resolveConfig(params: {\n readonly config: KiddConfig\n readonly cwd: string\n}): ResolvedBundlerConfig {\n const { config, cwd } = params\n\n const entry = resolve(cwd, config.entry ?? DEFAULT_ENTRY)\n const commands = resolve(cwd, config.commands ?? DEFAULT_COMMANDS)\n\n const buildOpts = config.build ?? {}\n const compileOpts = normalizeCompileOptions(config.compile)\n\n const buildOutDir = resolve(cwd, buildOpts.out ?? DEFAULT_OUT_DIR)\n const compileOutDir = resolve(cwd, compileOpts.out ?? DEFAULT_OUT_DIR)\n\n return {\n build: {\n external: buildOpts.external ?? [],\n minify: buildOpts.minify ?? DEFAULT_MINIFY,\n sourcemap: buildOpts.sourcemap ?? DEFAULT_SOURCEMAP,\n target: buildOpts.target ?? DEFAULT_TARGET,\n },\n buildOutDir,\n commands,\n compile: {\n name: compileOpts.name ?? DEFAULT_BINARY_NAME,\n targets: compileOpts.targets ?? [],\n },\n compileOutDir,\n cwd,\n entry,\n include: config.include ?? [],\n }\n}\n\n/**\n * Detect the bundled entry file in a build output directory.\n *\n * tsdown may produce `index.mjs` or `index.js` depending on the project's\n * `package.json` `type` field and tsdown configuration. This function checks\n * for both candidates and returns the first one that exists on disk.\n *\n * @param outDir - Absolute path to the build output directory.\n * @returns The absolute path to the entry file, or `undefined` when none is found.\n */\nexport function detectBuildEntry(outDir: string): string | undefined {\n return ENTRY_CANDIDATES.map((name) => join(outDir, name)).find(existsSync)\n}\n","import { err, ok } from '@kidd-cli/utils/fp'\nimport { build as tsdownBuild } from 'tsdown'\n\nimport { mapToBuildConfig } from './map-config.js'\nimport { detectBuildEntry, resolveConfig } from './resolve-config.js'\nimport type { AsyncBundlerResult, BuildOutput, BuildParams } from './types.js'\n\n/**\n * Build a kidd CLI tool using tsdown.\n *\n * Resolves defaults, maps the config to tsdown's InlineConfig, and invokes the build.\n *\n * @param params - The build parameters including config and working directory.\n * @returns A result tuple with build output on success or an Error on failure.\n */\nexport async function build(params: BuildParams): AsyncBundlerResult<BuildOutput> {\n const resolved = resolveConfig(params)\n const inlineConfig = mapToBuildConfig(resolved)\n\n try {\n await tsdownBuild(inlineConfig)\n } catch (error: unknown) {\n console.error('[kidd-bundler] build error:', error)\n return err(new Error('tsdown build failed', { cause: error }))\n }\n\n const entryFile = detectBuildEntry(resolved.buildOutDir)\n\n if (!entryFile) {\n return err(new Error(`build produced no entry file in ${resolved.buildOutDir}`))\n }\n\n return ok({\n entryFile,\n outDir: resolved.buildOutDir,\n })\n}\n","import { execFile as execFileCb } from 'node:child_process'\nimport { readdirSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { CompileTarget } from '@kidd-cli/config'\nimport { err, ok } from '@kidd-cli/utils/fp'\nimport type { AsyncResult } from '@kidd-cli/utils/fp'\n\nimport { DEFAULT_COMPILE_TARGETS } from './constants.js'\nimport { detectBuildEntry, resolveConfig } from './resolve-config.js'\nimport type { CompileOutput, CompileParams, CompiledBinary } from './types.js'\n\n/**\n * Packages to externalize during `bun build --compile`.\n *\n * These are optional peer dependencies of `c12` (the config loader) that bun\n * eagerly tries to resolve even though they are behind dynamic `import()` calls\n * that never execute at runtime in a compiled CLI.\n */\nconst COMPILE_EXTERNALS: readonly string[] = ['chokidar', 'magicast', 'giget']\n\n/**\n * Human-readable labels for each compile target.\n */\nconst COMPILE_TARGET_LABELS: Readonly<Record<CompileTarget, string>> = {\n 'darwin-arm64': 'macOS Apple Silicon',\n 'darwin-x64': 'macOS Intel',\n 'linux-arm64': 'Linux ARM64',\n 'linux-x64': 'Linux x64',\n 'linux-x64-musl': 'Linux x64 (musl)',\n 'windows-arm64': 'Windows ARM64',\n 'windows-x64': 'Windows x64',\n}\n\n/**\n * Compile a kidd CLI tool into standalone binaries using `bun build --compile`.\n *\n * Expects the bundled entry to already exist in `outDir` (i.e., `build()` must\n * be run first). For each requested target (or the current platform if none\n * specified), spawns `bun build --compile` to produce a self-contained binary.\n *\n * @param params - The compile parameters including config and working directory.\n * @returns A result tuple with compile output on success or an Error on failure.\n */\nexport async function compile(params: CompileParams): AsyncResult<CompileOutput> {\n const resolved = resolveConfig(params)\n const bundledEntry = detectBuildEntry(resolved.buildOutDir)\n\n if (!bundledEntry) {\n return err(new Error(`bundled entry not found in ${resolved.buildOutDir} — run build() first`))\n }\n\n const targets: readonly CompileTarget[] = resolveTargets(resolved.compile.targets)\n const isMultiTarget = targets.length > 1\n\n const results = await Promise.all(\n targets.map(async (target) => {\n if (params.onTargetStart) {\n await params.onTargetStart(target)\n }\n\n const result = await compileSingleTarget({\n bundledEntry,\n isMultiTarget,\n name: resolved.compile.name,\n outDir: resolved.compileOutDir,\n target,\n })\n\n if (params.onTargetComplete) {\n await params.onTargetComplete(target)\n }\n\n return result\n })\n )\n\n cleanBunBuildArtifacts(resolved.cwd)\n\n const failedResult = results.find((r) => r[0] !== null)\n if (failedResult) {\n const [failedError] = failedResult\n if (failedError) {\n return err(failedError)\n }\n }\n\n const binaries: readonly CompiledBinary[] = results\n .filter((r): r is readonly [null, CompiledBinary] => r[1] !== null)\n .map(([, binary]) => binary)\n\n return ok({ binaries })\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Compile a single target via `bun build --compile`.\n *\n * @private\n * @param params - Target compilation parameters.\n * @returns A result tuple with the compiled binary info or an error.\n */\nasync function compileSingleTarget(params: {\n readonly bundledEntry: string\n readonly outDir: string\n readonly name: string\n readonly target: CompileTarget\n readonly isMultiTarget: boolean\n}): AsyncResult<CompiledBinary> {\n const binaryName = resolveBinaryName(params.name, params.target, params.isMultiTarget)\n const outfile = join(params.outDir, binaryName)\n\n const args = [\n 'build',\n '--compile',\n params.bundledEntry,\n '--outfile',\n outfile,\n '--target',\n mapCompileTarget(params.target),\n ...COMPILE_EXTERNALS.flatMap((pkg) => ['--external', pkg]),\n ]\n\n const [execError] = await execBunBuild(args)\n if (execError) {\n return err(\n new Error(`bun build --compile failed for target ${params.target}`, { cause: execError })\n )\n }\n\n return ok({ label: resolveTargetLabel(params.target), path: outfile, target: params.target })\n}\n\n/**\n * Resolve the list of compile targets, falling back to the default set.\n *\n * When no targets are explicitly configured, defaults to linux-x64,\n * darwin-arm64, darwin-x64, and windows-x64 to cover ~95% of developers.\n *\n * @private\n * @param explicit - User-specified targets (may be empty).\n * @returns The targets to compile for.\n */\nfunction resolveTargets(explicit: readonly CompileTarget[]): readonly CompileTarget[] {\n if (explicit.length > 0) {\n return explicit\n }\n\n return DEFAULT_COMPILE_TARGETS\n}\n\n/**\n * Build the output binary name, appending the target suffix for multi-target builds.\n *\n * @private\n * @param name - Base binary name.\n * @param target - The compile target.\n * @param isMultiTarget - Whether multiple targets are being compiled.\n * @returns The resolved binary file name.\n */\nfunction resolveBinaryName(name: string, target: CompileTarget, isMultiTarget: boolean): string {\n if (isMultiTarget) {\n return `${name}-${target}`\n }\n\n return name\n}\n\n/**\n * Look up the human-readable label for a compile target.\n *\n * @param target - The compile target identifier.\n * @returns A descriptive label (e.g., \"macOS Apple Silicon\").\n */\nexport function resolveTargetLabel(target: CompileTarget): string {\n return COMPILE_TARGET_LABELS[target]\n}\n\n/**\n * Map a `CompileTarget` to Bun's `--target` string.\n *\n * Note: `linux-x64-musl` maps to `bun-linux-x64` because Bun's Linux\n * builds natively handle musl — there is no separate musl target.\n *\n * @private\n * @param target - The kidd compile target.\n * @returns The Bun target string (e.g., `'bun-darwin-arm64'`).\n */\nfunction mapCompileTarget(target: CompileTarget): string {\n if (target === 'linux-x64-musl') {\n return 'bun-linux-x64'\n }\n\n return `bun-${target}`\n}\n\n/**\n * Promisified wrapper around `execFile` to invoke `bun build`.\n *\n * @private\n * @param args - Arguments to pass to `bun`.\n * @returns A result tuple with stdout on success or an Error on failure.\n */\nfunction execBunBuild(args: readonly string[]): AsyncResult<string> {\n return new Promise((resolve) => {\n execFileCb('bun', [...args], (error, stdout) => {\n if (error) {\n resolve(err(error))\n return\n }\n\n resolve(ok(stdout))\n })\n })\n}\n\n/**\n * Remove temporary `.bun-build` files that `bun build --compile` leaves behind.\n *\n * @private\n * @param cwd - The working directory to clean.\n */\nfunction cleanBunBuildArtifacts(cwd: string): void {\n readdirSync(cwd)\n .filter((name) => name.endsWith('.bun-build'))\n .map((name) => join(cwd, name))\n .map(unlinkSync)\n}\n","import { err, ok } from '@kidd-cli/utils/fp'\nimport { build as tsdownBuild } from 'tsdown'\n\nimport { mapToWatchConfig } from './map-config.js'\nimport { resolveConfig } from './resolve-config.js'\nimport type { AsyncBundlerResult, WatchParams } from './types.js'\n\n/**\n * Start a watch-mode build for a kidd CLI tool using tsdown.\n *\n * The returned promise resolves only when tsdown's watch terminates (typically on process exit).\n * tsdown's `build()` with `watch: true` runs indefinitely.\n *\n * @param params - The watch parameters including config, working directory, and optional success callback.\n * @returns A result tuple with void on success or an Error on failure.\n */\nexport async function watch(params: WatchParams): AsyncBundlerResult<void> {\n const resolved = resolveConfig(params)\n const watchConfig = mapToWatchConfig({\n config: resolved,\n onSuccess: params.onSuccess,\n })\n\n try {\n await tsdownBuild(watchConfig)\n } catch (error: unknown) {\n return err(new Error('tsdown watch failed', { cause: error }))\n }\n\n return ok()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["tsdownBuild","tsdownBuild"],"sources":["../src/generate-autoloader.ts","../src/scan-commands.ts","../src/autoload-plugin.ts","../src/constants.ts","../src/map-config.ts","../src/read-version.ts","../src/resolve-config.ts","../src/build.ts","../src/compile.ts","../src/watch.ts"],"sourcesContent":["import type { ScanResult, ScannedDir, ScannedFile } from './types.js'\n\n/**\n * Parameters for generating a static autoloader module.\n */\ninterface GenerateStaticAutoloaderParams {\n readonly scan: ScanResult\n readonly tagModulePath: string\n}\n\n/**\n * The two parts of a static autoloader transform: import statements to\n * prepend and the replacement code for the autoloader region.\n */\nexport interface StaticAutoloaderParts {\n readonly imports: string\n readonly region: string\n}\n\n/**\n * Generate JavaScript source code for a static autoloader virtual module.\n *\n * The generated module statically imports every discovered command file and\n * exports an `autoload()` function that returns the pre-built CommandMap.\n * Directory commands that merge a parent handler with subcommands are re-tagged\n * via `withTag` because the TAG symbol is non-enumerable and lost on spread.\n *\n * @param params - The scan result and path to the tag utility module.\n * @returns JavaScript source code for the static autoloader.\n */\nexport function generateStaticAutoloader(params: GenerateStaticAutoloaderParams): string {\n const imports = collectImports(params.scan)\n const importLines = buildImportStatements(imports, params.tagModulePath)\n const commandsObject = buildCommandsObject(params.scan)\n\n return [\n ...importLines,\n '',\n `const commands = ${commandsObject}`,\n '',\n 'export async function autoload() {',\n ' return commands',\n '}',\n '',\n ].join('\\n')\n}\n\n/**\n * Generate the two parts needed to transform kidd's bundled dist.\n *\n * Returns an empty imports string (no prepended imports needed) and a\n * replacement autoloader region that uses dynamic `import()` calls inside\n * the async `autoload()` function. This avoids circular dependency issues:\n * command files import `command` from `@kidd-cli/core`, so static imports would be\n * hoisted above kidd's own initialization code, causing `TAG` to be\n * accessed before initialization.\n *\n * By deferring to dynamic imports, kidd fully initializes first, then\n * command files are loaded when `autoload()` is called at CLI startup.\n *\n * @param params - The scan result and path to the tag utility module.\n * @returns Import statements (empty) and the replacement autoloader region.\n */\nexport function generateAutoloaderParts(\n params: GenerateStaticAutoloaderParams\n): StaticAutoloaderParts {\n const imports = collectImports(params.scan)\n\n if (imports.length === 0) {\n return {\n imports: '',\n region: buildEmptyAutoloaderRegion(),\n }\n }\n\n const commandsObject = buildCommandsObject(params.scan)\n const region = buildDynamicAutoloaderRegion(imports, commandsObject)\n\n return { imports: '', region }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * A collected import entry with its identifier and absolute file path.\n *\n * @private\n */\ninterface ImportEntry {\n readonly identifier: string\n readonly filePath: string\n}\n\n/**\n * Collect all import entries from a scan result.\n *\n * @private\n * @param scan - The scan result to collect imports from.\n * @returns A flat array of all import entries.\n */\nfunction collectImports(scan: ScanResult): readonly ImportEntry[] {\n return [\n ...scan.files.map((file) => fileToImport(file, [])),\n ...scan.dirs.flatMap((dir) => collectDirImports(dir, [])),\n ]\n}\n\n/**\n * Recursively collect import entries from a scanned directory.\n *\n * @private\n * @param dir - The scanned directory.\n * @param parentPath - The path segments leading to this directory.\n * @returns A flat array of import entries for the directory and its children.\n */\nfunction collectDirImports(dir: ScannedDir, parentPath: readonly string[]): readonly ImportEntry[] {\n const currentPath = [...parentPath, dir.name]\n const indexImport: readonly ImportEntry[] = buildIndexImport(dir.index, currentPath)\n\n return [\n ...indexImport,\n ...dir.files.map((file) => fileToImport(file, currentPath)),\n ...dir.dirs.flatMap((sub) => collectDirImports(sub, currentPath)),\n ]\n}\n\n/**\n * Create an import entry for a leaf command file.\n *\n * @private\n * @param file - The scanned file.\n * @param parentPath - The path segments leading to the file's parent directory.\n * @returns An import entry with a generated identifier.\n */\nfunction fileToImport(file: ScannedFile, parentPath: readonly string[]): ImportEntry {\n return {\n filePath: file.filePath,\n identifier: toIdentifier([...parentPath, file.name]),\n }\n}\n\n/**\n * Convert a path segment array to a valid JavaScript identifier.\n *\n * Joins segments with underscores and prefixes with `_`.\n * Example: `['deploy', 'preview']` becomes `_deploy_preview`.\n *\n * @private\n * @param segments - The path segments to convert.\n * @returns A valid JavaScript identifier string.\n */\nfunction toIdentifier(segments: readonly string[]): string {\n return `_${segments.map((s) => s.replaceAll('-', '$')).join('_')}`\n}\n\n/**\n * Build the array of import statement lines.\n *\n * @private\n * @param imports - All collected import entries.\n * @param tagModulePath - Absolute path to the tag utility module.\n * @returns An array of import statement strings.\n */\nfunction buildImportStatements(\n imports: readonly ImportEntry[],\n tagModulePath: string\n): readonly string[] {\n const tagLine = buildTagImportLine(imports, tagModulePath)\n\n const importLines = imports.map((entry) => `import ${entry.identifier} from '${entry.filePath}'`)\n\n return [...tagLine, '', ...importLines]\n}\n\n/**\n * Build the JavaScript object literal string for the top-level commands map.\n *\n * @private\n * @param scan - The scan result.\n * @returns A string representation of the commands object literal.\n */\nfunction buildCommandsObject(scan: ScanResult): string {\n const entries = [\n ...scan.files.map((file) => buildFileEntry(file, [])),\n ...scan.dirs.map((dir) => buildDirEntry(dir, [])),\n ]\n\n return formatObject(entries)\n}\n\n/**\n * Build an object entry string for a leaf command file.\n *\n * @private\n * @param file - The scanned file.\n * @param parentPath - Path segments to the file's parent.\n * @returns A string like `'status': _status`.\n */\nfunction buildFileEntry(file: ScannedFile, parentPath: readonly string[]): string {\n const identifier = toIdentifier([...parentPath, file.name])\n return `'${file.name}': ${identifier}`\n}\n\n/**\n * Build an object entry string for a directory command (possibly with subcommands).\n *\n * @private\n * @param dir - The scanned directory.\n * @param parentPath - Path segments to the directory's parent.\n * @returns A string representing the directory command with withTag wrapping.\n */\nfunction buildDirEntry(dir: ScannedDir, parentPath: readonly string[]): string {\n const currentPath = [...parentPath, dir.name]\n const subEntries = [\n ...dir.files.map((file) => buildFileEntry(file, currentPath)),\n ...dir.dirs.map((sub) => buildDirEntry(sub, currentPath)),\n ]\n const commandsObj = formatObject(subEntries)\n\n if (dir.index) {\n const indexIdentifier = toIdentifier(currentPath)\n\n return `'${dir.name}': withTag({ ...${indexIdentifier}, commands: ${commandsObj} }, 'Command')`\n }\n\n return `'${dir.name}': withTag({ commands: ${commandsObj} }, 'Command')`\n}\n\n/**\n * Build the import entry for an index file, if present.\n *\n * @private\n * @param index - The absolute path to the index file, or undefined.\n * @param currentPath - The current path segments for identifier generation.\n * @returns An array with zero or one import entries.\n */\nfunction buildIndexImport(\n index: string | undefined,\n currentPath: readonly string[]\n): readonly ImportEntry[] {\n if (!index) {\n return []\n }\n return [{ filePath: index, identifier: toIdentifier(currentPath) }]\n}\n\n/**\n * Build the tag import line if any imports exist.\n *\n * @private\n * @param imports - The collected import entries.\n * @param tagModulePath - The absolute path to the tag module.\n * @returns An array with zero or one import statement strings.\n */\nfunction buildTagImportLine(\n imports: readonly ImportEntry[],\n tagModulePath: string\n): readonly string[] {\n if (imports.length === 0) {\n return []\n }\n return [`import { withTag } from '${tagModulePath}'`]\n}\n\n/**\n * Build the autoloader region for an empty scan result.\n *\n * @private\n * @returns A region string with an autoloader that returns an empty object.\n */\nfunction buildEmptyAutoloaderRegion(): string {\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ' return {}',\n '}',\n '//#endregion',\n ].join('\\n')\n}\n\n/**\n * Build the autoloader region using dynamic `import()` calls.\n *\n * Uses `Promise.all` with array destructuring to load all command files\n * in parallel. The dynamic imports defer execution until `autoload()` is\n * called, avoiding circular dependency issues with kidd's own initialization.\n *\n * @private\n * @param imports - The collected import entries.\n * @param commandsObject - The commands object literal string.\n * @returns A region string with the full dynamic autoloader.\n */\nfunction buildDynamicAutoloaderRegion(\n imports: readonly ImportEntry[],\n commandsObject: string\n): string {\n const destructuring = imports.map((entry) => ` { default: ${entry.identifier} },`).join('\\n')\n\n const importCalls = imports.map((entry) => ` import('${entry.filePath}'),`).join('\\n')\n\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ' const [',\n destructuring,\n ' ] = await Promise.all([',\n importCalls,\n ' ])',\n ` return ${commandsObject}`,\n '}',\n '//#endregion',\n ].join('\\n')\n}\n\n/**\n * Format an array of key-value strings as a JavaScript object literal.\n *\n * @private\n * @param entries - The key-value pair strings.\n * @returns A formatted object literal string.\n */\nfunction formatObject(entries: readonly string[]): string {\n if (entries.length === 0) {\n return '{}'\n }\n\n const body = entries.map((entry) => ` ${entry},`).join('\\n')\n return `{\\n${body}\\n}`\n}\n","import type { Dirent } from 'node:fs'\nimport { readdir } from 'node:fs/promises'\nimport { basename, extname, join } from 'node:path'\n\nimport type { ScanResult, ScannedDir, ScannedFile } from './types.js'\n\nconst VALID_EXTENSIONS = new Set(['.ts', '.js', '.mjs'])\nconst INDEX_NAME = 'index'\n\n/**\n * Scan a commands directory and produce a tree structure for static code generation.\n *\n * Mirrors the runtime autoloader's rules: valid extensions are `.ts`, `.js`, `.mjs`;\n * files and directories starting with `_` or `.` are skipped; `index` files in\n * subdirectories become parent command handlers.\n *\n * @param dir - Absolute path to the commands directory.\n * @returns A tree of scanned files and directories.\n */\nexport async function scanCommandsDir(dir: string): Promise<ScanResult> {\n const entries = await readdir(dir, { withFileTypes: true })\n\n const files = entries.filter(isCommandFile).map((entry) => toScannedFile(dir, entry))\n\n const dirs = await Promise.all(\n entries.filter(isCommandDir).map((entry) => scanSubDir(join(dir, entry.name)))\n )\n\n return { dirs, files }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively scan a subdirectory into a ScannedDir.\n *\n * @private\n * @param dir - Absolute path to the subdirectory.\n * @returns A ScannedDir representing the directory and its contents.\n */\nasync function scanSubDir(dir: string): Promise<ScannedDir> {\n const name = basename(dir)\n const entries = await readdir(dir, { withFileTypes: true })\n const indexEntry = findIndexEntry(entries)\n\n const files = entries.filter(isCommandFile).map((entry) => toScannedFile(dir, entry))\n\n const dirs = await Promise.all(\n entries.filter(isCommandDir).map((entry) => scanSubDir(join(dir, entry.name)))\n )\n\n return {\n dirs,\n files,\n index: resolveIndexPath(dir, indexEntry),\n name,\n }\n}\n\n/**\n * Convert a directory entry into a ScannedFile.\n *\n * @private\n * @param dir - Parent directory absolute path.\n * @param entry - The directory entry for the file.\n * @returns A ScannedFile with name and absolute file path.\n */\nfunction toScannedFile(dir: string, entry: Dirent): ScannedFile {\n return {\n filePath: join(dir, entry.name),\n name: basename(entry.name, extname(entry.name)),\n }\n}\n\n/**\n * Find the index file entry among a list of directory entries.\n *\n * @private\n * @param entries - The directory entries to search.\n * @returns The Dirent for the index file, or undefined.\n */\nfunction findIndexEntry(entries: readonly Dirent[]): Dirent | undefined {\n return entries.find(\n (entry) =>\n entry.isFile() &&\n VALID_EXTENSIONS.has(extname(entry.name)) &&\n basename(entry.name, extname(entry.name)) === INDEX_NAME\n )\n}\n\n/**\n * Predicate: entry is a valid command file (not index, not hidden/private).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a scannable command file.\n */\nfunction isCommandFile(entry: Dirent): boolean {\n if (!entry.isFile()) {\n return false\n }\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) {\n return false\n }\n if (!VALID_EXTENSIONS.has(extname(entry.name))) {\n return false\n }\n return basename(entry.name, extname(entry.name)) !== INDEX_NAME\n}\n\n/**\n * Predicate: entry is a scannable command directory (not hidden/private).\n *\n * @private\n * @param entry - The directory entry to check.\n * @returns True when the entry is a scannable command directory.\n */\nfunction isCommandDir(entry: Dirent): boolean {\n if (!entry.isDirectory()) {\n return false\n }\n return !entry.name.startsWith('_') && !entry.name.startsWith('.')\n}\n\n/**\n * Resolve the absolute path to an index file entry, or undefined.\n *\n * @private\n * @param dir - The parent directory absolute path.\n * @param entry - The index file Dirent, or undefined.\n * @returns The absolute path to the index file, or undefined.\n */\nfunction resolveIndexPath(dir: string, entry: Dirent | undefined): string | undefined {\n if (!entry) {\n return undefined\n }\n return join(dir, entry.name)\n}\n","import type { Rolldown } from 'tsdown'\n\nimport { generateStaticAutoloader } from './generate-autoloader.js'\nimport { scanCommandsDir } from './scan-commands.js'\n\nconst VIRTUAL_MODULE_ID = 'virtual:kidd-static-commands'\nconst RESOLVED_VIRTUAL_ID = `\\0${VIRTUAL_MODULE_ID}`\n\nconst AUTOLOADER_REGION_START = '//#region src/autoloader.ts'\nconst AUTOLOADER_REGION_END = '//#endregion'\n\n/**\n * Parameters for creating the autoload plugin.\n */\ninterface CreateAutoloadPluginParams {\n readonly commandsDir: string\n readonly tagModulePath: string\n}\n\n/**\n * Create a rolldown plugin that replaces the runtime autoloader with a static version.\n *\n * Uses a three-hook approach to break the circular dependency between kidd's\n * dist and user command files (which `import { command } from '@kidd-cli/core'`):\n *\n * 1. `transform` — detects kidd's pre-bundled dist and replaces the autoloader\n * region with a dynamic `import()` to a virtual module\n * 2. `resolveId` — resolves the virtual module identifier\n * 3. `load` — scans the commands directory and generates a static autoloader\n * module with all command imports pre-resolved\n *\n * The dynamic import ensures command files execute after kidd's code is fully\n * initialized, avoiding `ReferenceError` from accessing `TAG` before its\n * declaration.\n *\n * @param params - The commands directory and tag module path.\n * @returns A rolldown plugin for static autoloading.\n */\nexport function createAutoloadPlugin(params: CreateAutoloadPluginParams): Rolldown.Plugin {\n return {\n async load(id) {\n if (id !== RESOLVED_VIRTUAL_ID) {\n return null\n }\n\n const scan = await scanCommandsDir(params.commandsDir)\n\n return generateStaticAutoloader({\n scan,\n tagModulePath: params.tagModulePath,\n })\n },\n name: 'kidd-static-autoloader',\n resolveId(source) {\n if (source === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_ID\n }\n\n return null\n },\n transform(code, _id) {\n const regionStart = code.indexOf(AUTOLOADER_REGION_START)\n if (regionStart === -1) {\n return null\n }\n\n const regionEnd = code.indexOf(AUTOLOADER_REGION_END, regionStart)\n if (regionEnd === -1) {\n return null\n }\n\n const before = code.slice(0, regionStart)\n const after = code.slice(regionEnd + AUTOLOADER_REGION_END.length)\n const staticRegion = buildStaticRegion()\n\n return `${before}${staticRegion}${after}`\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Build the replacement autoloader region that delegates to the virtual module.\n *\n * @private\n * @returns The replacement region string with dynamic import.\n */\nfunction buildStaticRegion(): string {\n return [\n '//#region src/autoloader.ts (static)',\n 'async function autoload() {',\n ` const mod = await import('${VIRTUAL_MODULE_ID}')`,\n ' return mod.autoload()',\n '}',\n '//#endregion',\n ].join('\\n')\n}\n","import { builtinModules } from 'node:module'\n\nimport type { CompileTarget } from '@kidd-cli/config'\n\n/**\n * Shebang line prepended to CLI entry files.\n */\nexport const SHEBANG = '#!/usr/bin/env node\\n'\n\n/**\n * Default entry point for the CLI source.\n */\nexport const DEFAULT_ENTRY = './src/index.ts'\n\n/**\n * Default directory for CLI commands.\n */\nexport const DEFAULT_COMMANDS = './commands'\n\n/**\n * Default build output directory.\n */\nexport const DEFAULT_OUT_DIR = './dist'\n\n/**\n * Default Node.js target version for builds.\n */\nexport const DEFAULT_TARGET = 'node18'\n\n/**\n * Default minification setting.\n */\nexport const DEFAULT_MINIFY = false\n\n/**\n * Default source map generation setting.\n */\nexport const DEFAULT_SOURCEMAP = true\n\n/**\n * Default binary name for compiled SEA output.\n */\nexport const DEFAULT_BINARY_NAME = 'cli'\n\n/**\n * Default compile targets when none are explicitly configured.\n *\n * Covers Linux servers/CI, modern and Intel Macs, and Windows — roughly 95%\n * of developer environments.\n */\nexport const DEFAULT_COMPILE_TARGETS: readonly CompileTarget[] = [\n 'darwin-arm64',\n 'darwin-x64',\n 'linux-x64',\n 'windows-x64',\n]\n\n/**\n * Packages that must always be bundled into the output.\n *\n * The `@kidd-cli/core` framework and its internal `@kidd-cli/*` packages must be inlined\n * so the autoload plugin can intercept and replace the runtime autoloader\n * with a static version for compiled binaries.\n */\nexport const ALWAYS_BUNDLE: RegExp[] = [/^@?kidd/]\n\n/**\n * Node.js builtin modules in both bare and `node:` prefixed forms.\n */\nexport const NODE_BUILTINS: readonly string[] = [\n ...builtinModules,\n ...builtinModules.map((m) => `node:${m}`),\n]\n","import { createRequire } from 'node:module'\n\nimport { match } from 'ts-pattern'\nimport type { InlineConfig } from 'tsdown'\n\nimport { createAutoloadPlugin } from './autoload-plugin.js'\nimport { ALWAYS_BUNDLE, NODE_BUILTINS, SHEBANG } from './constants.js'\nimport type { ResolvedBundlerConfig } from './types.js'\n\n/**\n * Map a resolved bundler config to a tsdown InlineConfig for production builds.\n *\n * @param params - The resolved config and optional version for compile-time injection.\n * @returns A tsdown InlineConfig ready for `build()`.\n */\nexport function mapToBuildConfig(params: {\n readonly config: ResolvedBundlerConfig\n readonly version?: string\n}): InlineConfig {\n return {\n banner: SHEBANG,\n clean: true,\n config: false,\n cwd: params.config.cwd,\n define: buildDefine(params.version),\n deps: {\n alwaysBundle: ALWAYS_BUNDLE,\n neverBundle: buildExternals(params.config.build.external),\n },\n dts: false,\n entry: { index: params.config.entry },\n format: 'esm',\n inputOptions: {\n resolve: {\n mainFields: ['module', 'main'],\n },\n },\n logLevel: 'silent',\n minify: params.config.build.minify,\n outDir: params.config.buildOutDir,\n outputOptions: {\n codeSplitting: false,\n },\n platform: 'node',\n plugins: [\n createAutoloadPlugin({\n commandsDir: params.config.commands,\n tagModulePath: resolveTagModulePath(),\n }),\n ],\n sourcemap: params.config.build.sourcemap,\n target: params.config.build.target,\n treeshake: true,\n }\n}\n\n/**\n * Map a resolved bundler config to a tsdown InlineConfig for watch mode.\n *\n * @param params - The resolved config, optional version, and optional success callback.\n * @returns A tsdown InlineConfig with `watch: true`.\n */\nexport function mapToWatchConfig(params: {\n readonly config: ResolvedBundlerConfig\n readonly version?: string\n readonly onSuccess?: () => void | Promise<void>\n}): InlineConfig {\n const buildConfig = mapToBuildConfig({ config: params.config, version: params.version })\n\n return {\n ...buildConfig,\n logLevel: 'error',\n onSuccess: params.onSuccess,\n watch: true,\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Combine Node.js builtins with user-specified externals.\n *\n * @private\n * @param userExternals - Additional packages to mark as external.\n * @returns Combined array of externals for tsdown's `deps.neverBundle`.\n */\nfunction buildExternals(userExternals: readonly string[]): (string | RegExp)[] {\n return [...NODE_BUILTINS, ...userExternals]\n}\n\n/**\n * Build the `define` map for compile-time constants.\n *\n * Injects `__KIDD_VERSION__` when a version string is available so that\n * the runtime can auto-detect the CLI version without reading package.json.\n *\n * @private\n * @param version - The version string from package.json, or undefined.\n * @returns A define map for tsdown/rolldown.\n */\nfunction buildDefine(version: string | undefined): Record<string, string> {\n return match(version)\n .with(undefined, () => ({}))\n .otherwise((resolvedVersion) => ({\n __KIDD_VERSION__: JSON.stringify(resolvedVersion),\n }))\n}\n\n/**\n * Resolve the absolute file path to the `@kidd-cli/utils/tag` module.\n *\n * The static autoloader virtual module imports `withTag` via this path.\n * Using an absolute path ensures rolldown can resolve the import from\n * inside the virtual module without relying on tsdown's `alwaysBundle`\n * heuristic, which virtual modules may bypass.\n *\n * @private\n * @returns The absolute file path to the tag module.\n */\nfunction resolveTagModulePath(): string {\n const require = createRequire(import.meta.url)\n return require.resolve('@kidd-cli/utils/tag')\n}\n","import { readManifest } from '@kidd-cli/utils/manifest'\n\nimport type { AsyncBundlerResult } from './types.js'\n\n/**\n * Read the version string from a project's package.json.\n *\n * Uses `readManifest` to parse the package.json at the given directory and\n * extracts the `version` field. Returns `undefined` when the manifest has no\n * version set.\n *\n * @param cwd - Directory containing the package.json.\n * @returns A result tuple with the version string (or undefined) on success, or an Error on failure.\n */\nexport async function readVersion(cwd: string): AsyncBundlerResult<string | undefined> {\n const [manifestError, manifest] = await readManifest(cwd)\n\n if (manifestError) {\n return [new Error(`Failed to read version: ${manifestError.message}`), null]\n }\n\n return [null, manifest.version]\n}\n","import { existsSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport type { CompileOptions, KiddConfig } from '@kidd-cli/config'\n\nimport {\n DEFAULT_BINARY_NAME,\n DEFAULT_COMMANDS,\n DEFAULT_ENTRY,\n DEFAULT_MINIFY,\n DEFAULT_OUT_DIR,\n DEFAULT_SOURCEMAP,\n DEFAULT_TARGET,\n} from './constants.js'\nimport type { ResolvedBundlerConfig } from './types.js'\n\n/**\n * Known entry file names produced by tsdown for ESM builds, in preference order.\n */\nconst ENTRY_CANDIDATES = ['index.mjs', 'index.js'] as const\n\n/**\n * Normalize the `compile` config field from `boolean | CompileOptions | undefined` to `CompileOptions`.\n *\n * - `true` → `{}` (compile with defaults)\n * - `false` / `undefined` → `{}` (no explicit options, caller decides whether to compile)\n * - object → pass through\n *\n * @param value - The raw compile config value.\n * @returns A normalized CompileOptions object.\n */\nexport function normalizeCompileOptions(\n value: boolean | CompileOptions | undefined\n): CompileOptions {\n if (typeof value === 'object') {\n return value\n }\n\n return {}\n}\n\n/**\n * Fill defaults and resolve relative paths against `cwd`.\n *\n * This is a pure function — the incoming config is already validated by `@kidd-cli/config`.\n * It only fills missing optional fields with defaults and resolves paths to absolute.\n *\n * @param params - The raw config and working directory.\n * @returns A fully resolved bundler configuration.\n */\nexport function resolveConfig(params: {\n readonly config: KiddConfig\n readonly cwd: string\n}): ResolvedBundlerConfig {\n const { config, cwd } = params\n\n const entry = resolve(cwd, config.entry ?? DEFAULT_ENTRY)\n const commands = resolve(cwd, config.commands ?? DEFAULT_COMMANDS)\n\n const buildOpts = config.build ?? {}\n const compileOpts = normalizeCompileOptions(config.compile)\n\n const buildOutDir = resolve(cwd, buildOpts.out ?? DEFAULT_OUT_DIR)\n const compileOutDir = resolve(cwd, compileOpts.out ?? DEFAULT_OUT_DIR)\n\n return {\n build: {\n external: buildOpts.external ?? [],\n minify: buildOpts.minify ?? DEFAULT_MINIFY,\n sourcemap: buildOpts.sourcemap ?? DEFAULT_SOURCEMAP,\n target: buildOpts.target ?? DEFAULT_TARGET,\n },\n buildOutDir,\n commands,\n compile: {\n name: compileOpts.name ?? DEFAULT_BINARY_NAME,\n targets: compileOpts.targets ?? [],\n },\n compileOutDir,\n cwd,\n entry,\n include: config.include ?? [],\n }\n}\n\n/**\n * Detect the bundled entry file in a build output directory.\n *\n * tsdown may produce `index.mjs` or `index.js` depending on the project's\n * `package.json` `type` field and tsdown configuration. This function checks\n * for both candidates and returns the first one that exists on disk.\n *\n * @param outDir - Absolute path to the build output directory.\n * @returns The absolute path to the entry file, or `undefined` when none is found.\n */\nexport function detectBuildEntry(outDir: string): string | undefined {\n return ENTRY_CANDIDATES.map((name) => join(outDir, name)).find(existsSync)\n}\n","import { err, ok } from '@kidd-cli/utils/fp'\nimport { build as tsdownBuild } from 'tsdown'\n\nimport { mapToBuildConfig } from './map-config.js'\nimport { readVersion } from './read-version.js'\nimport { detectBuildEntry, resolveConfig } from './resolve-config.js'\nimport type { AsyncBundlerResult, BuildOutput, BuildParams } from './types.js'\n\n/**\n * Build a kidd CLI tool using tsdown.\n *\n * Resolves defaults, reads the project version from package.json, maps the\n * config to tsdown's InlineConfig (injecting `__KIDD_VERSION__`), and invokes\n * the build.\n *\n * @param params - The build parameters including config and working directory.\n * @returns A result tuple with build output on success or an Error on failure.\n */\nexport async function build(params: BuildParams): AsyncBundlerResult<BuildOutput> {\n const resolved = resolveConfig(params)\n\n const [versionError, versionResult] = await readVersion(params.cwd)\n if (versionError) {\n console.warn('[kidd-bundler] could not read version from package.json:', versionError.message)\n }\n const version = versionResult ?? undefined\n\n const inlineConfig = mapToBuildConfig({ config: resolved, version })\n\n try {\n await tsdownBuild(inlineConfig)\n } catch (error: unknown) {\n console.error('[kidd-bundler] build error:', error)\n return err(new Error('tsdown build failed', { cause: error }))\n }\n\n const entryFile = detectBuildEntry(resolved.buildOutDir)\n\n if (!entryFile) {\n return err(new Error(`build produced no entry file in ${resolved.buildOutDir}`))\n }\n\n return ok({\n entryFile,\n outDir: resolved.buildOutDir,\n version,\n })\n}\n","import { execFile as execFileCb } from 'node:child_process'\nimport { readdirSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { CompileTarget } from '@kidd-cli/config'\nimport { err, ok } from '@kidd-cli/utils/fp'\nimport type { AsyncResult } from '@kidd-cli/utils/fp'\n\nimport { DEFAULT_COMPILE_TARGETS } from './constants.js'\nimport { detectBuildEntry, resolveConfig } from './resolve-config.js'\nimport type { CompileOutput, CompileParams, CompiledBinary } from './types.js'\n\n/**\n * Packages to externalize during `bun build --compile`.\n *\n * These are optional peer dependencies of `c12` (the config loader) that bun\n * eagerly tries to resolve even though they are behind dynamic `import()` calls\n * that never execute at runtime in a compiled CLI.\n */\nconst COMPILE_EXTERNALS: readonly string[] = ['chokidar', 'magicast', 'giget']\n\n/**\n * Human-readable labels for each compile target.\n */\nconst COMPILE_TARGET_LABELS: Readonly<Record<CompileTarget, string>> = {\n 'darwin-arm64': 'macOS Apple Silicon',\n 'darwin-x64': 'macOS Intel',\n 'linux-arm64': 'Linux ARM64',\n 'linux-x64': 'Linux x64',\n 'linux-x64-musl': 'Linux x64 (musl)',\n 'windows-arm64': 'Windows ARM64',\n 'windows-x64': 'Windows x64',\n}\n\n/**\n * Compile a kidd CLI tool into standalone binaries using `bun build --compile`.\n *\n * Expects the bundled entry to already exist in `outDir` (i.e., `build()` must\n * be run first). For each requested target (or the current platform if none\n * specified), spawns `bun build --compile` to produce a self-contained binary.\n *\n * @param params - The compile parameters including config and working directory.\n * @returns A result tuple with compile output on success or an Error on failure.\n */\nexport async function compile(params: CompileParams): AsyncResult<CompileOutput> {\n const resolved = resolveConfig(params)\n const bundledEntry = detectBuildEntry(resolved.buildOutDir)\n\n if (!bundledEntry) {\n return err(new Error(`bundled entry not found in ${resolved.buildOutDir} — run build() first`))\n }\n\n const targets: readonly CompileTarget[] = resolveTargets(resolved.compile.targets)\n const isMultiTarget = targets.length > 1\n\n const results = await Promise.all(\n targets.map(async (target) => {\n if (params.onTargetStart) {\n await params.onTargetStart(target)\n }\n\n const result = await compileSingleTarget({\n bundledEntry,\n isMultiTarget,\n name: resolved.compile.name,\n outDir: resolved.compileOutDir,\n target,\n })\n\n if (params.onTargetComplete) {\n await params.onTargetComplete(target)\n }\n\n return result\n })\n )\n\n cleanBunBuildArtifacts(resolved.cwd)\n\n const failedResult = results.find((r) => r[0] !== null)\n if (failedResult) {\n const [failedError] = failedResult\n if (failedError) {\n return err(failedError)\n }\n }\n\n const binaries: readonly CompiledBinary[] = results\n .filter((r): r is readonly [null, CompiledBinary] => r[1] !== null)\n .map(([, binary]) => binary)\n\n return ok({ binaries })\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Compile a single target via `bun build --compile`.\n *\n * @private\n * @param params - Target compilation parameters.\n * @returns A result tuple with the compiled binary info or an error.\n */\nasync function compileSingleTarget(params: {\n readonly bundledEntry: string\n readonly outDir: string\n readonly name: string\n readonly target: CompileTarget\n readonly isMultiTarget: boolean\n}): AsyncResult<CompiledBinary> {\n const binaryName = resolveBinaryName(params.name, params.target, params.isMultiTarget)\n const outfile = join(params.outDir, binaryName)\n\n const args = [\n 'build',\n '--compile',\n params.bundledEntry,\n '--outfile',\n outfile,\n '--target',\n mapCompileTarget(params.target),\n ...COMPILE_EXTERNALS.flatMap((pkg) => ['--external', pkg]),\n ]\n\n const [execError] = await execBunBuild(args)\n if (execError) {\n return err(\n new Error(`bun build --compile failed for target ${params.target}`, { cause: execError })\n )\n }\n\n return ok({ label: resolveTargetLabel(params.target), path: outfile, target: params.target })\n}\n\n/**\n * Resolve the list of compile targets, falling back to the default set.\n *\n * When no targets are explicitly configured, defaults to linux-x64,\n * darwin-arm64, darwin-x64, and windows-x64 to cover ~95% of developers.\n *\n * @private\n * @param explicit - User-specified targets (may be empty).\n * @returns The targets to compile for.\n */\nfunction resolveTargets(explicit: readonly CompileTarget[]): readonly CompileTarget[] {\n if (explicit.length > 0) {\n return explicit\n }\n\n return DEFAULT_COMPILE_TARGETS\n}\n\n/**\n * Build the output binary name, appending the target suffix for multi-target builds.\n *\n * @private\n * @param name - Base binary name.\n * @param target - The compile target.\n * @param isMultiTarget - Whether multiple targets are being compiled.\n * @returns The resolved binary file name.\n */\nfunction resolveBinaryName(name: string, target: CompileTarget, isMultiTarget: boolean): string {\n if (isMultiTarget) {\n return `${name}-${target}`\n }\n\n return name\n}\n\n/**\n * Look up the human-readable label for a compile target.\n *\n * @param target - The compile target identifier.\n * @returns A descriptive label (e.g., \"macOS Apple Silicon\").\n */\nexport function resolveTargetLabel(target: CompileTarget): string {\n return COMPILE_TARGET_LABELS[target]\n}\n\n/**\n * Map a `CompileTarget` to Bun's `--target` string.\n *\n * Note: `linux-x64-musl` maps to `bun-linux-x64` because Bun's Linux\n * builds natively handle musl — there is no separate musl target.\n *\n * @private\n * @param target - The kidd compile target.\n * @returns The Bun target string (e.g., `'bun-darwin-arm64'`).\n */\nfunction mapCompileTarget(target: CompileTarget): string {\n if (target === 'linux-x64-musl') {\n return 'bun-linux-x64'\n }\n\n return `bun-${target}`\n}\n\n/**\n * Promisified wrapper around `execFile` to invoke `bun build`.\n *\n * @private\n * @param args - Arguments to pass to `bun`.\n * @returns A result tuple with stdout on success or an Error on failure.\n */\nfunction execBunBuild(args: readonly string[]): AsyncResult<string> {\n return new Promise((resolve) => {\n execFileCb('bun', [...args], (error, stdout) => {\n if (error) {\n resolve(err(error))\n return\n }\n\n resolve(ok(stdout))\n })\n })\n}\n\n/**\n * Remove temporary `.bun-build` files that `bun build --compile` leaves behind.\n *\n * @private\n * @param cwd - The working directory to clean.\n */\nfunction cleanBunBuildArtifacts(cwd: string): void {\n readdirSync(cwd)\n .filter((name) => name.endsWith('.bun-build'))\n .map((name) => join(cwd, name))\n .map(unlinkSync)\n}\n","import { err, ok } from '@kidd-cli/utils/fp'\nimport { build as tsdownBuild } from 'tsdown'\n\nimport { mapToWatchConfig } from './map-config.js'\nimport { readVersion } from './read-version.js'\nimport { resolveConfig } from './resolve-config.js'\nimport type { AsyncBundlerResult, WatchParams } from './types.js'\n\n/**\n * Start a watch-mode build for a kidd CLI tool using tsdown.\n *\n * The returned promise resolves only when tsdown's watch terminates (typically on process exit).\n * tsdown's `build()` with `watch: true` runs indefinitely.\n *\n * @param params - The watch parameters including config, working directory, and optional success callback.\n * @returns A result tuple with void on success or an Error on failure.\n */\nexport async function watch(params: WatchParams): AsyncBundlerResult<void> {\n const resolved = resolveConfig(params)\n\n const [versionError, versionResult] = await readVersion(params.cwd)\n if (versionError) {\n console.warn('[kidd-bundler] could not read version from package.json:', versionError.message)\n }\n const version = versionResult ?? undefined\n\n const watchConfig = mapToWatchConfig({\n config: resolved,\n onSuccess: params.onSuccess,\n version,\n })\n\n try {\n await tsdownBuild(watchConfig)\n } catch (error: unknown) {\n return err(new Error('tsdown watch failed', { cause: error }))\n }\n\n return ok()\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kidd-cli/bundler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Programmatic bundler for kidd CLI tools powered by tsdown",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"ts-pattern": "^5.9.0",
|
|
24
24
|
"tsdown": "0.21.1",
|
|
25
25
|
"zod": "^4.3.6",
|
|
26
|
-
"@kidd-cli/config": "0.1.
|
|
27
|
-
"@kidd-cli/utils": "0.1.
|
|
26
|
+
"@kidd-cli/config": "0.1.4",
|
|
27
|
+
"@kidd-cli/utils": "0.1.4"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^25.4.0",
|