outfitter 0.3.2 → 0.3.3
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/README.md +33 -5
- package/dist/actions/add.d.ts +18 -0
- package/dist/actions/add.js +14 -0
- package/dist/actions/check-automation.d.ts +20 -0
- package/dist/actions/check-automation.js +27 -0
- package/dist/actions/check.d.ts +34 -0
- package/dist/actions/check.js +19 -0
- package/dist/actions/demo.d.ts +12 -0
- package/dist/actions/demo.js +11 -0
- package/dist/actions/docs-output-mode.d.ts +4 -0
- package/dist/actions/docs-output-mode.js +8 -0
- package/dist/actions/docs.d.ts +25 -0
- package/dist/actions/docs.js +31 -0
- package/dist/actions/doctor.d.ts +10 -0
- package/dist/actions/doctor.js +15 -0
- package/dist/actions/init.d.ts +28 -0
- package/dist/actions/init.js +31 -0
- package/dist/actions/scaffold.d.ts +19 -0
- package/dist/actions/scaffold.js +21 -0
- package/dist/actions/shared.d.ts +61 -0
- package/dist/actions/shared.js +30 -0
- package/dist/actions/upgrade.d.ts +17 -0
- package/dist/actions/upgrade.js +21 -0
- package/dist/actions.d.ts +2 -0
- package/dist/actions.js +66 -0
- package/dist/cli.js +66 -4
- package/dist/commands/add.d.ts +54 -0
- package/dist/commands/add.js +16 -0
- package/dist/commands/check-action-ceremony.d.ts +55 -0
- package/dist/commands/check-action-ceremony.js +15 -0
- package/dist/commands/check-docs-sentinel.d.ts +27 -0
- package/dist/commands/check-docs-sentinel.js +18 -0
- package/dist/commands/check-orchestrator.d.ts +2 -0
- package/dist/commands/check-orchestrator.js +17 -0
- package/dist/commands/check-preset-versions.d.ts +20 -0
- package/dist/commands/check-preset-versions.js +15 -0
- package/dist/commands/check-publish-guardrails.d.ts +38 -0
- package/dist/commands/check-publish-guardrails.js +19 -0
- package/dist/commands/check-surface-map-format.d.ts +29 -0
- package/dist/commands/check-surface-map-format.js +19 -0
- package/dist/commands/check-surface-map.d.ts +20 -0
- package/dist/commands/check-surface-map.js +15 -0
- package/dist/commands/check-tsdoc.d.ts +3 -0
- package/dist/commands/check-tsdoc.js +9 -0
- package/dist/commands/check.d.ts +93 -0
- package/dist/commands/check.js +14 -0
- package/dist/commands/demo.d.ts +21 -0
- package/dist/commands/demo.js +8 -0
- package/dist/commands/docs-api.d.ts +4 -0
- package/dist/commands/docs-api.js +13 -0
- package/dist/commands/docs-export.d.ts +4 -0
- package/dist/commands/docs-export.js +12 -0
- package/dist/commands/docs-list.d.ts +3 -0
- package/dist/commands/docs-list.js +13 -0
- package/dist/commands/docs-module-loader.d.ts +2 -0
- package/dist/commands/docs-module-loader.js +8 -0
- package/dist/commands/docs-search.d.ts +3 -0
- package/dist/commands/docs-search.js +13 -0
- package/dist/commands/docs-show.d.ts +3 -0
- package/dist/commands/docs-show.js +13 -0
- package/dist/commands/docs-types.d.ts +21 -0
- package/dist/commands/docs-types.js +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +17 -0
- package/dist/commands/init-execution.d.ts +8 -0
- package/dist/commands/init-execution.js +11 -0
- package/dist/commands/init-option-resolution.d.ts +5 -0
- package/dist/commands/init-option-resolution.js +14 -0
- package/dist/commands/init-output.d.ts +9 -0
- package/dist/commands/init-output.js +11 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +24 -0
- package/dist/commands/jq-utils.d.ts +17 -0
- package/dist/commands/jq-utils.js +8 -0
- package/dist/commands/repo.d.ts +3 -0
- package/dist/commands/repo.js +13 -0
- package/dist/commands/scaffold-output.d.ts +4 -0
- package/dist/commands/scaffold-output.js +11 -0
- package/dist/commands/scaffold-planning.d.ts +65 -0
- package/dist/commands/scaffold-planning.js +20 -0
- package/dist/commands/scaffold.d.ts +4 -0
- package/dist/commands/scaffold.js +26 -0
- package/dist/commands/shared-deps.d.ts +22 -0
- package/dist/commands/shared-deps.js +11 -0
- package/dist/commands/upgrade-apply.d.ts +14 -0
- package/dist/commands/upgrade-apply.js +8 -0
- package/dist/commands/upgrade-codemods.d.ts +47 -0
- package/dist/commands/upgrade-codemods.js +14 -0
- package/dist/commands/upgrade-latest-version.d.ts +8 -0
- package/dist/commands/upgrade-latest-version.js +8 -0
- package/dist/commands/upgrade-migration-docs.d.ts +3 -0
- package/dist/commands/upgrade-migration-docs.js +15 -0
- package/dist/commands/upgrade-migration-frontmatter.d.ts +2 -0
- package/dist/commands/upgrade-migration-frontmatter.js +10 -0
- package/dist/commands/upgrade-migration-guides.d.ts +5 -0
- package/dist/commands/upgrade-migration-guides.js +10 -0
- package/dist/commands/upgrade-output.d.ts +5 -0
- package/dist/commands/upgrade-output.js +11 -0
- package/dist/commands/upgrade-planner.d.ts +58 -0
- package/dist/commands/upgrade-planner.js +8 -0
- package/dist/commands/upgrade-report.d.ts +5 -0
- package/dist/commands/upgrade-report.js +8 -0
- package/dist/commands/upgrade-workspace.d.ts +2 -0
- package/dist/commands/upgrade-workspace.js +16 -0
- package/dist/commands/upgrade.d.ts +5 -0
- package/dist/commands/upgrade.js +37 -0
- package/dist/create/index.d.ts +5 -0
- package/dist/create/index.js +2 -0
- package/dist/create/planner.d.ts +3 -0
- package/dist/create/planner.js +85 -0
- package/dist/create/presets.d.ts +3 -0
- package/dist/create/presets.js +12 -0
- package/dist/create/types.d.ts +2 -0
- package/dist/create/types.js +1 -0
- package/dist/engine/blocks.d.ts +3 -0
- package/dist/engine/blocks.js +12 -0
- package/dist/engine/collector.d.ts +2 -0
- package/dist/engine/collector.js +8 -0
- package/dist/engine/config.d.ts +3 -0
- package/dist/engine/config.js +15 -0
- package/dist/engine/dependency-versions.d.ts +17 -0
- package/dist/engine/dependency-versions.js +12 -0
- package/dist/engine/executor.d.ts +3 -0
- package/dist/engine/executor.js +156 -0
- package/dist/engine/index.d.ts +10 -0
- package/dist/engine/index.js +54 -0
- package/dist/engine/names.d.ts +2 -0
- package/dist/engine/names.js +24 -0
- package/dist/engine/post-scaffold.d.ts +3 -0
- package/dist/engine/post-scaffold.js +8 -0
- package/dist/engine/preset.d.ts +3 -0
- package/dist/engine/preset.js +17 -0
- package/dist/engine/render-plan.d.ts +7 -0
- package/dist/engine/render-plan.js +9 -0
- package/dist/engine/template.d.ts +4 -0
- package/dist/engine/template.js +34 -0
- package/dist/engine/types.d.ts +2 -0
- package/dist/engine/types.js +8 -0
- package/dist/engine/workspace.d.ts +3 -0
- package/dist/engine/workspace.js +20 -0
- package/dist/index.d.ts +17 -397
- package/dist/index.js +7 -165
- package/dist/manifest.d.ts +71 -0
- package/dist/manifest.js +16 -0
- package/dist/output-mode.d.ts +2 -0
- package/dist/output-mode.js +10 -0
- package/dist/shared/outfitter-109s75x0.d.ts +76 -0
- package/dist/shared/outfitter-1fy7byz5.js +170 -0
- package/dist/shared/outfitter-1h7k8xxt.js +29 -0
- package/dist/shared/outfitter-1tfa9hke.d.ts +55 -0
- package/dist/shared/outfitter-2nx0k4b3.d.ts +4 -0
- package/dist/shared/outfitter-2ysjerp6.d.ts +44 -0
- package/dist/shared/outfitter-2z61gp5w.js +29 -0
- package/dist/shared/outfitter-34vg353f.d.ts +82 -0
- package/dist/shared/outfitter-3dq4r10s.d.ts +24 -0
- package/dist/shared/outfitter-3rcrvva8.js +103 -0
- package/dist/shared/outfitter-3tx3adgj.js +278 -0
- package/dist/shared/outfitter-4q1zfmvc.js +154 -0
- package/dist/shared/outfitter-4s9meh3j.js +221 -0
- package/dist/shared/outfitter-507ra35w.js +285 -0
- package/dist/shared/outfitter-56jq0rh2.d.ts +42 -0
- package/dist/shared/outfitter-58rn1sj1.d.ts +30 -0
- package/dist/shared/outfitter-5d9wbzhh.d.ts +19 -0
- package/dist/shared/outfitter-5j7zee11.d.ts +180 -0
- package/dist/shared/outfitter-5r6q2749.d.ts +18 -0
- package/dist/shared/outfitter-5vx1bp7h.js +41 -0
- package/dist/shared/outfitter-6ddf91vh.js +190 -0
- package/dist/shared/outfitter-6mpkh3zn.js +432 -0
- package/dist/shared/outfitter-6rtcemk7.d.ts +18 -0
- package/dist/shared/outfitter-6t7xeyg1.js +159 -0
- package/dist/shared/outfitter-738z4c37.js +262 -0
- package/dist/shared/outfitter-76k25svs.js +322 -0
- package/dist/shared/outfitter-7n7vsz95.js +101 -0
- package/dist/shared/outfitter-7q9fnbwa.js +60 -0
- package/dist/shared/outfitter-7r12fj7f.js +30 -0
- package/dist/shared/outfitter-84chvazx.js +480 -0
- package/dist/shared/outfitter-8ggmja91.js +301 -0
- package/dist/shared/outfitter-8kmak0wc.d.ts +4 -0
- package/dist/shared/outfitter-8y2dfx6n.js +11 -0
- package/dist/shared/outfitter-940h0x7b.js +71 -0
- package/dist/shared/outfitter-954y4mzx.d.ts +5 -0
- package/dist/shared/outfitter-a79xrm12.d.ts +17 -0
- package/dist/shared/outfitter-b9cpnr7e.js +110 -0
- package/dist/shared/outfitter-bpr28y54.js +70 -0
- package/dist/shared/outfitter-c7sbs7es.js +92 -0
- package/dist/shared/outfitter-cyhzstz0.js +93 -0
- package/dist/shared/outfitter-cyvr4r8d.d.ts +67 -0
- package/dist/shared/outfitter-d0kqashd.d.ts +98 -0
- package/dist/shared/outfitter-dx4hn4ta.js +325 -0
- package/dist/shared/outfitter-e84cr97g.js +232 -0
- package/dist/shared/outfitter-ec83h4v2.js +17 -0
- package/dist/shared/outfitter-eepj7rf7.js +4 -0
- package/dist/shared/outfitter-ekb6t1zz.js +35 -0
- package/dist/shared/outfitter-ex8gn945.js +51 -0
- package/dist/shared/outfitter-f3a70135.js +75 -0
- package/dist/shared/outfitter-fbvfd5zq.d.ts +13 -0
- package/dist/shared/outfitter-fj2v5ffz.js +165 -0
- package/dist/shared/outfitter-fx1m251y.js +122 -0
- package/dist/shared/outfitter-fxry5n58.js +254 -0
- package/dist/shared/outfitter-g3hvjshg.js +1 -0
- package/dist/shared/outfitter-gdc7b7de.d.ts +5 -0
- package/dist/shared/outfitter-gyayfx5r.js +156 -0
- package/dist/shared/outfitter-h0wmtxw8.d.ts +23 -0
- package/dist/shared/outfitter-hcexcvxe.d.ts +25 -0
- package/dist/shared/outfitter-hf5bj2gq.js +117 -0
- package/dist/shared/outfitter-hsp8vy5m.d.ts +146 -0
- package/dist/shared/outfitter-htx4asgr.d.ts +52 -0
- package/dist/shared/outfitter-jkct38dh.js +53 -0
- package/dist/shared/outfitter-jwxggvz4.js +42 -0
- package/dist/shared/outfitter-k6zyvg2n.js +306 -0
- package/dist/shared/outfitter-ksyvwmb5.js +191 -0
- package/dist/shared/outfitter-m3ehh37q.d.ts +22 -0
- package/dist/shared/outfitter-mstr60zz.js +215 -0
- package/dist/shared/outfitter-n0ed012k.js +101 -0
- package/dist/shared/outfitter-n13pqaft.js +19 -0
- package/dist/shared/outfitter-nxvjxrmw.d.ts +48 -0
- package/dist/shared/outfitter-p2wn07b7.js +160 -0
- package/dist/shared/outfitter-px5sv5gn.js +321 -0
- package/dist/shared/outfitter-q1g58t85.js +8 -0
- package/dist/shared/outfitter-qsd5638j.js +378 -0
- package/dist/shared/outfitter-qsrx7m4w.js +72 -0
- package/dist/shared/outfitter-r2awqszh.d.ts +52 -0
- package/dist/shared/outfitter-rdpw2sbp.d.ts +77 -0
- package/dist/shared/outfitter-rp89dafm.js +109 -0
- package/dist/shared/outfitter-s1c0whzj.js +121 -0
- package/dist/shared/outfitter-ssrtakh3.js +342 -0
- package/dist/shared/outfitter-ssynegbs.js +167 -0
- package/dist/shared/outfitter-svts4wk2.js +36 -0
- package/dist/shared/outfitter-tavatb5p.js +166 -0
- package/dist/shared/outfitter-tqznjgbm.js +44 -0
- package/dist/shared/outfitter-ttjr95y9.js +98 -0
- package/dist/shared/outfitter-wcrp7d7m.d.ts +5 -0
- package/dist/shared/outfitter-wkt0a0ra.js +67 -0
- package/dist/shared/outfitter-wrcqq29p.js +132 -0
- package/dist/shared/outfitter-wyg1tpp5.d.ts +43 -0
- package/dist/shared/outfitter-x0vpb7tj.js +126 -0
- package/dist/shared/outfitter-x39awx8g.js +146 -0
- package/dist/shared/outfitter-x4cc5xsq.js +168 -0
- package/dist/shared/outfitter-x8w5sjnd.d.ts +39 -0
- package/dist/shared/outfitter-xr6g13nz.d.ts +50 -0
- package/dist/shared/outfitter-xs94pkfe.js +106 -0
- package/dist/shared/outfitter-y37yfehn.d.ts +37 -0
- package/dist/shared/outfitter-y6ee0k45.d.ts +18 -0
- package/dist/shared/outfitter-ydw7x6bh.js +61 -0
- package/dist/shared/outfitter-yhb23pjc.js +89 -0
- package/dist/shared/outfitter-ypcvwg1s.js +91 -0
- package/dist/shared/outfitter-znbqe5zy.d.ts +45 -0
- package/dist/shared/outfitter-zng6w0t9.d.ts +4 -0
- package/dist/targets/index.d.ts +4 -0
- package/dist/targets/index.js +28 -0
- package/dist/targets/registry.d.ts +3 -0
- package/dist/targets/registry.js +221 -0
- package/dist/targets/types.d.ts +2 -0
- package/dist/targets/types.js +1 -0
- package/package.json +194 -35
- package/dist/shared/chunk-3pwh8ys4.js +0 -6461
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
printInitResults
|
|
4
|
+
} from "./outfitter-n0ed012k.js";
|
|
5
|
+
import {
|
|
6
|
+
isBinaryPreset,
|
|
7
|
+
parseBlocks,
|
|
8
|
+
resolvePresetFromFlags
|
|
9
|
+
} from "./outfitter-2z61gp5w.js";
|
|
10
|
+
import {
|
|
11
|
+
executeInitPipeline
|
|
12
|
+
} from "./outfitter-tavatb5p.js";
|
|
13
|
+
import {
|
|
14
|
+
INIT_TARGET_IDS,
|
|
15
|
+
TARGET_REGISTRY,
|
|
16
|
+
getInitTarget
|
|
17
|
+
} from "./outfitter-g3hvjshg.js";
|
|
18
|
+
import {
|
|
19
|
+
deriveBinName,
|
|
20
|
+
deriveProjectName,
|
|
21
|
+
resolvePackageName,
|
|
22
|
+
sanitizePackageName,
|
|
23
|
+
validatePackageName
|
|
24
|
+
} from "./outfitter-q1g58t85.js";
|
|
25
|
+
|
|
26
|
+
// apps/outfitter/src/commands/init.ts
|
|
27
|
+
import { basename, resolve } from "path";
|
|
28
|
+
import {
|
|
29
|
+
cancel,
|
|
30
|
+
confirm,
|
|
31
|
+
intro,
|
|
32
|
+
isCancel,
|
|
33
|
+
outro,
|
|
34
|
+
select,
|
|
35
|
+
text
|
|
36
|
+
} from "@clack/prompts";
|
|
37
|
+
import { exitWithError } from "@outfitter/cli";
|
|
38
|
+
import { Result } from "@outfitter/contracts";
|
|
39
|
+
class InitError extends Error {
|
|
40
|
+
_tag = "InitError";
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "InitError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function resolveInitInput(options, presetOverride) {
|
|
47
|
+
const rootDir = resolve(options.targetDir);
|
|
48
|
+
const defaultName = basename(rootDir);
|
|
49
|
+
const defaultPackageName = sanitizePackageName(defaultName) || defaultName;
|
|
50
|
+
const presetFromFlagsResult = resolvePresetFromFlags(options.preset, INIT_TARGET_IDS);
|
|
51
|
+
if (presetFromFlagsResult.isErr()) {
|
|
52
|
+
return Result.err(new InitError(presetFromFlagsResult.error));
|
|
53
|
+
}
|
|
54
|
+
const presetFromFlags = presetFromFlagsResult.value;
|
|
55
|
+
if (options.yes || !process.stdout.isTTY) {
|
|
56
|
+
const packageNameRaw = resolvePackageName(rootDir, options.name).trim();
|
|
57
|
+
const packageName2 = options.name === undefined ? sanitizePackageName(packageNameRaw) : packageNameRaw;
|
|
58
|
+
if (packageName2.length === 0) {
|
|
59
|
+
return Result.err(new InitError("Project name must not be empty"));
|
|
60
|
+
}
|
|
61
|
+
const invalidPackageName2 = validatePackageName(packageName2);
|
|
62
|
+
if (invalidPackageName2) {
|
|
63
|
+
const suggested = sanitizePackageName(packageNameRaw);
|
|
64
|
+
const suggestion = suggested.length > 0 && suggested !== packageNameRaw ? ` Try '${suggested}'.` : "";
|
|
65
|
+
return Result.err(new InitError(`Invalid package name '${packageNameRaw}': ${invalidPackageName2}.${suggestion}`));
|
|
66
|
+
}
|
|
67
|
+
const preset = presetOverride ?? presetFromFlags ?? "minimal";
|
|
68
|
+
const structure = preset === "full-stack" ? "single" : options.structure ?? "single";
|
|
69
|
+
const blocksOverride2 = parseBlocks(options.with);
|
|
70
|
+
const workspaceName2 = structure === "workspace" ? (options.workspaceName ?? defaultPackageName).trim() || defaultPackageName : undefined;
|
|
71
|
+
if (workspaceName2) {
|
|
72
|
+
const invalidWorkspaceName = validatePackageName(workspaceName2);
|
|
73
|
+
if (invalidWorkspaceName) {
|
|
74
|
+
return Result.err(new InitError(`Invalid workspace package name '${workspaceName2}': ${invalidWorkspaceName}`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Result.ok({
|
|
78
|
+
rootDir,
|
|
79
|
+
packageName: packageName2,
|
|
80
|
+
preset,
|
|
81
|
+
structure,
|
|
82
|
+
includeTooling: !(options.noTooling ?? false),
|
|
83
|
+
local: Boolean(options.local),
|
|
84
|
+
...blocksOverride2 ? { blocksOverride: blocksOverride2 } : {},
|
|
85
|
+
...workspaceName2 ? { workspaceName: workspaceName2 } : {},
|
|
86
|
+
...options.bin ? { binName: options.bin } : {}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
intro("Outfitter init");
|
|
90
|
+
const packageNameValue = options.name ?? await text({
|
|
91
|
+
message: "Project package name",
|
|
92
|
+
placeholder: defaultPackageName,
|
|
93
|
+
initialValue: defaultPackageName,
|
|
94
|
+
validate: (value) => (value ?? "").trim().length === 0 ? "Project name is required" : undefined
|
|
95
|
+
});
|
|
96
|
+
if (isCancel(packageNameValue)) {
|
|
97
|
+
cancel("Init cancelled.");
|
|
98
|
+
return Result.err(new InitError("Init cancelled"));
|
|
99
|
+
}
|
|
100
|
+
const presetValue = presetOverride ?? presetFromFlags ?? await select({
|
|
101
|
+
message: "Select a preset",
|
|
102
|
+
options: INIT_TARGET_IDS.map((id) => {
|
|
103
|
+
const target = TARGET_REGISTRY.get(id);
|
|
104
|
+
return {
|
|
105
|
+
value: id,
|
|
106
|
+
label: id,
|
|
107
|
+
hint: target?.description ?? ""
|
|
108
|
+
};
|
|
109
|
+
}),
|
|
110
|
+
initialValue: "minimal"
|
|
111
|
+
});
|
|
112
|
+
if (isCancel(presetValue)) {
|
|
113
|
+
cancel("Init cancelled.");
|
|
114
|
+
return Result.err(new InitError("Init cancelled"));
|
|
115
|
+
}
|
|
116
|
+
const structureValue = presetValue === "full-stack" ? "single" : options.structure ?? await select({
|
|
117
|
+
message: "Project structure",
|
|
118
|
+
options: [
|
|
119
|
+
{
|
|
120
|
+
value: "single",
|
|
121
|
+
label: "Single package",
|
|
122
|
+
hint: "One package in the target directory"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
value: "workspace",
|
|
126
|
+
label: "Workspace",
|
|
127
|
+
hint: "Root workspace with project under apps/ or packages/"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
initialValue: "single"
|
|
131
|
+
});
|
|
132
|
+
if (isCancel(structureValue)) {
|
|
133
|
+
cancel("Init cancelled.");
|
|
134
|
+
return Result.err(new InitError("Init cancelled"));
|
|
135
|
+
}
|
|
136
|
+
let binName;
|
|
137
|
+
if (isBinaryPreset(presetValue) && process.stdout.isTTY) {
|
|
138
|
+
const defaultBin = deriveBinName(deriveProjectName(packageNameValue.trim()));
|
|
139
|
+
const binValue = options.bin ?? await text({
|
|
140
|
+
message: "Binary name",
|
|
141
|
+
placeholder: defaultBin,
|
|
142
|
+
initialValue: defaultBin
|
|
143
|
+
});
|
|
144
|
+
if (isCancel(binValue)) {
|
|
145
|
+
cancel("Init cancelled.");
|
|
146
|
+
return Result.err(new InitError("Init cancelled"));
|
|
147
|
+
}
|
|
148
|
+
binName = binValue.trim();
|
|
149
|
+
}
|
|
150
|
+
let includeTooling;
|
|
151
|
+
if (options.noTooling !== undefined) {
|
|
152
|
+
includeTooling = !options.noTooling;
|
|
153
|
+
} else if (options.with !== undefined) {
|
|
154
|
+
includeTooling = true;
|
|
155
|
+
} else {
|
|
156
|
+
includeTooling = await confirm({
|
|
157
|
+
message: "Add default tooling blocks?",
|
|
158
|
+
initialValue: true
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (isCancel(includeTooling)) {
|
|
162
|
+
cancel("Init cancelled.");
|
|
163
|
+
return Result.err(new InitError("Init cancelled"));
|
|
164
|
+
}
|
|
165
|
+
const localValue = options.local !== undefined ? options.local : await confirm({
|
|
166
|
+
message: "Use workspace:* for @outfitter dependencies?",
|
|
167
|
+
initialValue: false
|
|
168
|
+
});
|
|
169
|
+
if (isCancel(localValue)) {
|
|
170
|
+
cancel("Init cancelled.");
|
|
171
|
+
return Result.err(new InitError("Init cancelled"));
|
|
172
|
+
}
|
|
173
|
+
let workspaceName;
|
|
174
|
+
if (structureValue === "workspace") {
|
|
175
|
+
const workspaceNameValue = options.workspaceName ?? await text({
|
|
176
|
+
message: "Workspace package name",
|
|
177
|
+
placeholder: defaultPackageName,
|
|
178
|
+
initialValue: defaultPackageName,
|
|
179
|
+
validate: (value) => (value ?? "").trim().length === 0 ? "Workspace name is required" : undefined
|
|
180
|
+
});
|
|
181
|
+
if (isCancel(workspaceNameValue)) {
|
|
182
|
+
cancel("Init cancelled.");
|
|
183
|
+
return Result.err(new InitError("Init cancelled"));
|
|
184
|
+
}
|
|
185
|
+
workspaceName = workspaceNameValue.trim();
|
|
186
|
+
}
|
|
187
|
+
outro("Scaffolding project...");
|
|
188
|
+
const packageName = packageNameValue.trim();
|
|
189
|
+
if (packageName.length === 0) {
|
|
190
|
+
return Result.err(new InitError("Project name must not be empty"));
|
|
191
|
+
}
|
|
192
|
+
const invalidPackageName = validatePackageName(packageName);
|
|
193
|
+
if (invalidPackageName) {
|
|
194
|
+
const suggested = sanitizePackageName(packageName);
|
|
195
|
+
const suggestion = suggested.length > 0 && suggested !== packageName ? ` Try '${suggested}'.` : "";
|
|
196
|
+
return Result.err(new InitError(`Invalid package name '${packageName}': ${invalidPackageName}.${suggestion}`));
|
|
197
|
+
}
|
|
198
|
+
if (workspaceName) {
|
|
199
|
+
const invalidWorkspaceName = validatePackageName(workspaceName);
|
|
200
|
+
if (invalidWorkspaceName) {
|
|
201
|
+
return Result.err(new InitError(`Invalid workspace package name '${workspaceName}': ${invalidWorkspaceName}`));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const blocksOverride = parseBlocks(options.with);
|
|
205
|
+
return Result.ok({
|
|
206
|
+
rootDir,
|
|
207
|
+
packageName,
|
|
208
|
+
preset: presetValue,
|
|
209
|
+
structure: structureValue,
|
|
210
|
+
includeTooling,
|
|
211
|
+
local: Boolean(localValue),
|
|
212
|
+
...blocksOverride ? { blocksOverride } : {},
|
|
213
|
+
...workspaceName ? { workspaceName } : {},
|
|
214
|
+
...binName ? { binName } : {}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async function runInit(options, presetOverride) {
|
|
218
|
+
const inputResult = await resolveInitInput(options, presetOverride);
|
|
219
|
+
if (inputResult.isErr()) {
|
|
220
|
+
return inputResult;
|
|
221
|
+
}
|
|
222
|
+
const input = inputResult.value;
|
|
223
|
+
const targetResult = getInitTarget(input.preset);
|
|
224
|
+
if (targetResult.isErr()) {
|
|
225
|
+
return Result.err(new InitError(targetResult.error.message));
|
|
226
|
+
}
|
|
227
|
+
const executeResult = await executeInitPipeline(input, targetResult.value, {
|
|
228
|
+
dryRun: Boolean(options.dryRun),
|
|
229
|
+
force: options.force,
|
|
230
|
+
skipInstall: Boolean(options.skipInstall),
|
|
231
|
+
skipGit: Boolean(options.skipGit),
|
|
232
|
+
skipCommit: Boolean(options.skipCommit),
|
|
233
|
+
installTimeout: options.installTimeout ?? 60000
|
|
234
|
+
});
|
|
235
|
+
if (executeResult.isErr()) {
|
|
236
|
+
return Result.err(new InitError(executeResult.error));
|
|
237
|
+
}
|
|
238
|
+
return Result.ok(executeResult.value);
|
|
239
|
+
}
|
|
240
|
+
var resolveLocal = (flags) => {
|
|
241
|
+
if (flags.local === true || flags.workspace === true) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
};
|
|
246
|
+
var resolveOutputMode = (flags) => {
|
|
247
|
+
if (flags.json) {
|
|
248
|
+
return "json";
|
|
249
|
+
}
|
|
250
|
+
return;
|
|
251
|
+
};
|
|
252
|
+
var withCommonOptions = (command) => command.option("-n, --name <name>", "Package name (defaults to directory name)").option("-b, --bin <name>", "Binary name (defaults to project name)").option("-p, --preset <preset>", "Preset to use (minimal|cli|mcp|daemon|library|full-stack)").option("-s, --structure <mode>", "Project structure (single|workspace)").option("--workspace-name <name>", "Workspace root package name").option("-f, --force", "Overwrite existing files", false).option("--local", "Use workspace:* for @outfitter dependencies").option("--workspace", "Alias for --local").option("--with <blocks>", "Comma-separated tooling blocks to add").option("--no-tooling", "Skip default tooling blocks").option("-y, --yes", "Skip prompts and use defaults", false).option("--dry-run", "Preview changes without writing files", false).option("--skip-install", "Skip bun install", false).option("--skip-git", "Skip git init and initial commit", false).option("--skip-commit", "Skip initial commit only", false).option("--install-timeout <ms>", "bun install timeout in ms");
|
|
253
|
+
function initCommand(program) {
|
|
254
|
+
const init = program.command("init").description("Create a new Outfitter project");
|
|
255
|
+
const resolveFlags = (flags, command) => {
|
|
256
|
+
if (command) {
|
|
257
|
+
return command.optsWithGlobals();
|
|
258
|
+
}
|
|
259
|
+
return typeof flags.opts === "function" ? flags.opts() : flags;
|
|
260
|
+
};
|
|
261
|
+
withCommonOptions(init.argument("[directory]")).action(async (directory, flags, command) => {
|
|
262
|
+
const targetDir = directory ?? process.cwd();
|
|
263
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
264
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
265
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
266
|
+
const result = await runInit({
|
|
267
|
+
targetDir,
|
|
268
|
+
name: resolvedFlags.name,
|
|
269
|
+
bin: resolvedFlags.bin,
|
|
270
|
+
preset: resolvedFlags.preset,
|
|
271
|
+
structure: resolvedFlags.structure,
|
|
272
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
273
|
+
local: resolveLocal(resolvedFlags),
|
|
274
|
+
force: resolvedFlags.force ?? false,
|
|
275
|
+
with: resolvedFlags.with,
|
|
276
|
+
noTooling: resolvedFlags.noTooling,
|
|
277
|
+
yes: resolvedFlags.yes,
|
|
278
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
279
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
280
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
281
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
282
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
283
|
+
});
|
|
284
|
+
if (result.isErr()) {
|
|
285
|
+
exitWithError(result.error, outputOptions);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
await printInitResults(result.value, outputOptions);
|
|
289
|
+
});
|
|
290
|
+
withCommonOptions(init.command("cli [directory]").description("Create a new CLI project")).action(async (directory, flags, command) => {
|
|
291
|
+
const targetDir = directory ?? process.cwd();
|
|
292
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
293
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
294
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
295
|
+
const result = await runInit({
|
|
296
|
+
targetDir,
|
|
297
|
+
name: resolvedFlags.name,
|
|
298
|
+
bin: resolvedFlags.bin,
|
|
299
|
+
structure: resolvedFlags.structure,
|
|
300
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
301
|
+
local: resolveLocal(resolvedFlags),
|
|
302
|
+
force: resolvedFlags.force ?? false,
|
|
303
|
+
with: resolvedFlags.with,
|
|
304
|
+
noTooling: resolvedFlags.noTooling,
|
|
305
|
+
yes: resolvedFlags.yes,
|
|
306
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
307
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
308
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
309
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
310
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
311
|
+
}, "cli");
|
|
312
|
+
if (result.isErr()) {
|
|
313
|
+
exitWithError(result.error, outputOptions);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
await printInitResults(result.value, outputOptions);
|
|
317
|
+
});
|
|
318
|
+
withCommonOptions(init.command("mcp [directory]").description("Create a new MCP server")).action(async (directory, flags, command) => {
|
|
319
|
+
const targetDir = directory ?? process.cwd();
|
|
320
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
321
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
322
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
323
|
+
const result = await runInit({
|
|
324
|
+
targetDir,
|
|
325
|
+
name: resolvedFlags.name,
|
|
326
|
+
bin: resolvedFlags.bin,
|
|
327
|
+
structure: resolvedFlags.structure,
|
|
328
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
329
|
+
local: resolveLocal(resolvedFlags),
|
|
330
|
+
force: resolvedFlags.force ?? false,
|
|
331
|
+
with: resolvedFlags.with,
|
|
332
|
+
noTooling: resolvedFlags.noTooling,
|
|
333
|
+
yes: resolvedFlags.yes,
|
|
334
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
335
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
336
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
337
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
338
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
339
|
+
}, "mcp");
|
|
340
|
+
if (result.isErr()) {
|
|
341
|
+
exitWithError(result.error, outputOptions);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
await printInitResults(result.value, outputOptions);
|
|
345
|
+
});
|
|
346
|
+
withCommonOptions(init.command("daemon [directory]").description("Create a new daemon project")).action(async (directory, flags, command) => {
|
|
347
|
+
const targetDir = directory ?? process.cwd();
|
|
348
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
349
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
350
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
351
|
+
const result = await runInit({
|
|
352
|
+
targetDir,
|
|
353
|
+
name: resolvedFlags.name,
|
|
354
|
+
bin: resolvedFlags.bin,
|
|
355
|
+
structure: resolvedFlags.structure,
|
|
356
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
357
|
+
local: resolveLocal(resolvedFlags),
|
|
358
|
+
force: resolvedFlags.force ?? false,
|
|
359
|
+
with: resolvedFlags.with,
|
|
360
|
+
noTooling: resolvedFlags.noTooling,
|
|
361
|
+
yes: resolvedFlags.yes,
|
|
362
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
363
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
364
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
365
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
366
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
367
|
+
}, "daemon");
|
|
368
|
+
if (result.isErr()) {
|
|
369
|
+
exitWithError(result.error, outputOptions);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
await printInitResults(result.value, outputOptions);
|
|
373
|
+
});
|
|
374
|
+
withCommonOptions(init.command("library [directory]").description("Create a new library")).action(async (directory, flags, command) => {
|
|
375
|
+
const targetDir = directory ?? process.cwd();
|
|
376
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
377
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
378
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
379
|
+
const result = await runInit({
|
|
380
|
+
targetDir,
|
|
381
|
+
name: resolvedFlags.name,
|
|
382
|
+
bin: resolvedFlags.bin,
|
|
383
|
+
structure: resolvedFlags.structure,
|
|
384
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
385
|
+
local: resolveLocal(resolvedFlags),
|
|
386
|
+
force: resolvedFlags.force ?? false,
|
|
387
|
+
with: resolvedFlags.with,
|
|
388
|
+
noTooling: resolvedFlags.noTooling,
|
|
389
|
+
yes: resolvedFlags.yes,
|
|
390
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
391
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
392
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
393
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
394
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
395
|
+
}, "library");
|
|
396
|
+
if (result.isErr()) {
|
|
397
|
+
exitWithError(result.error, outputOptions);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
await printInitResults(result.value, outputOptions);
|
|
401
|
+
});
|
|
402
|
+
withCommonOptions(init.command("full-stack [directory]").description("Create a full-stack workspace")).action(async (directory, flags, command) => {
|
|
403
|
+
const targetDir = directory ?? process.cwd();
|
|
404
|
+
const resolvedFlags = resolveFlags(flags, command);
|
|
405
|
+
const mode = resolveOutputMode(resolvedFlags);
|
|
406
|
+
const outputOptions = mode ? { mode } : undefined;
|
|
407
|
+
const result = await runInit({
|
|
408
|
+
targetDir,
|
|
409
|
+
name: resolvedFlags.name,
|
|
410
|
+
bin: resolvedFlags.bin,
|
|
411
|
+
structure: resolvedFlags.structure,
|
|
412
|
+
workspaceName: resolvedFlags.workspaceName,
|
|
413
|
+
local: resolveLocal(resolvedFlags),
|
|
414
|
+
force: resolvedFlags.force ?? false,
|
|
415
|
+
with: resolvedFlags.with,
|
|
416
|
+
noTooling: resolvedFlags.noTooling,
|
|
417
|
+
yes: resolvedFlags.yes,
|
|
418
|
+
dryRun: Boolean(resolvedFlags.dryRun),
|
|
419
|
+
skipInstall: Boolean(resolvedFlags.skipInstall),
|
|
420
|
+
skipGit: Boolean(resolvedFlags.skipGit),
|
|
421
|
+
skipCommit: Boolean(resolvedFlags.skipCommit),
|
|
422
|
+
...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
|
|
423
|
+
}, "full-stack");
|
|
424
|
+
if (result.isErr()) {
|
|
425
|
+
exitWithError(result.error, outputOptions);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
await printInitResults(result.value, outputOptions);
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export { InitError, runInit, initCommand };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EngineOptions, PlaceholderValues, ScaffoldError } from "./outfitter-cyvr4r8d.js";
|
|
2
|
+
import { Result } from "@outfitter/contracts";
|
|
3
|
+
/**
|
|
4
|
+
* Get the directory containing scaffold preset files.
|
|
5
|
+
* Delegates to `@outfitter/presets` which is the single source of truth.
|
|
6
|
+
*/
|
|
7
|
+
declare function getPresetsBaseDir(): string;
|
|
8
|
+
declare function getOutputFilename(templateFilename: string): string;
|
|
9
|
+
declare function isBinaryFile(filename: string): boolean;
|
|
10
|
+
declare function replacePlaceholders(content: string, values: PlaceholderValues): string;
|
|
11
|
+
declare function copyPresetFiles(presetDir: string, targetDir: string, values: PlaceholderValues, options: EngineOptions, copyOptions?: {
|
|
12
|
+
readonly allowOverwrite?: boolean;
|
|
13
|
+
readonly overwritablePaths?: ReadonlySet<string>;
|
|
14
|
+
readonly writtenPaths?: Set<string>;
|
|
15
|
+
readonly skipFilter?: (relativePath: string) => boolean;
|
|
16
|
+
readonly relativePrefix?: string;
|
|
17
|
+
}): Result<void, ScaffoldError>;
|
|
18
|
+
export { getPresetsBaseDir, getOutputFilename, isBinaryFile, replacePlaceholders, copyPresetFiles };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
ScaffoldError
|
|
4
|
+
} from "./outfitter-8y2dfx6n.js";
|
|
5
|
+
|
|
6
|
+
// apps/outfitter/src/engine/preset.ts
|
|
7
|
+
import {
|
|
8
|
+
existsSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readdirSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
statSync,
|
|
13
|
+
writeFileSync
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { extname, join } from "path";
|
|
16
|
+
import { Result } from "@outfitter/contracts";
|
|
17
|
+
import { getPresetsDir } from "@outfitter/presets";
|
|
18
|
+
var BINARY_EXTENSIONS = new Set([
|
|
19
|
+
".png",
|
|
20
|
+
".jpg",
|
|
21
|
+
".jpeg",
|
|
22
|
+
".gif",
|
|
23
|
+
".ico",
|
|
24
|
+
".webp",
|
|
25
|
+
".bmp",
|
|
26
|
+
".tiff",
|
|
27
|
+
".svg",
|
|
28
|
+
".woff",
|
|
29
|
+
".woff2",
|
|
30
|
+
".ttf",
|
|
31
|
+
".otf",
|
|
32
|
+
".eot",
|
|
33
|
+
".mp3",
|
|
34
|
+
".mp4",
|
|
35
|
+
".wav",
|
|
36
|
+
".ogg",
|
|
37
|
+
".webm",
|
|
38
|
+
".zip",
|
|
39
|
+
".tar",
|
|
40
|
+
".gz",
|
|
41
|
+
".bz2",
|
|
42
|
+
".7z",
|
|
43
|
+
".pdf",
|
|
44
|
+
".exe",
|
|
45
|
+
".dll",
|
|
46
|
+
".so",
|
|
47
|
+
".dylib",
|
|
48
|
+
".node",
|
|
49
|
+
".wasm",
|
|
50
|
+
".bin",
|
|
51
|
+
".dat",
|
|
52
|
+
".db",
|
|
53
|
+
".sqlite",
|
|
54
|
+
".sqlite3"
|
|
55
|
+
]);
|
|
56
|
+
function getPresetsBaseDir() {
|
|
57
|
+
return getPresetsDir();
|
|
58
|
+
}
|
|
59
|
+
function getOutputFilename(templateFilename) {
|
|
60
|
+
return templateFilename.endsWith(".template") ? templateFilename.slice(0, -".template".length) : templateFilename;
|
|
61
|
+
}
|
|
62
|
+
function isBinaryFile(filename) {
|
|
63
|
+
return BINARY_EXTENSIONS.has(extname(filename).toLowerCase());
|
|
64
|
+
}
|
|
65
|
+
function replacePlaceholders(content, values) {
|
|
66
|
+
return content.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
67
|
+
if (Object.hasOwn(values, key)) {
|
|
68
|
+
return values[key];
|
|
69
|
+
}
|
|
70
|
+
return match;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function copyPresetFiles(presetDir, targetDir, values, options, copyOptions) {
|
|
74
|
+
const allowOverwrite = copyOptions?.allowOverwrite ?? false;
|
|
75
|
+
const relativePrefix = copyOptions?.relativePrefix ?? "";
|
|
76
|
+
try {
|
|
77
|
+
if (!existsSync(targetDir)) {
|
|
78
|
+
if (options.collector) {
|
|
79
|
+
options.collector.add({
|
|
80
|
+
type: "dir-create",
|
|
81
|
+
path: targetDir
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
mkdirSync(targetDir, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const entries = readdirSync(presetDir);
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
const sourcePath = join(presetDir, entry);
|
|
90
|
+
const sourceStat = statSync(sourcePath);
|
|
91
|
+
const relativePath = relativePrefix ? `${relativePrefix}/${entry}` : entry;
|
|
92
|
+
if (copyOptions?.skipFilter?.(relativePath)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (sourceStat.isDirectory()) {
|
|
96
|
+
const targetSubDir = join(targetDir, entry);
|
|
97
|
+
const nestedResult = copyPresetFiles(sourcePath, targetSubDir, values, options, {
|
|
98
|
+
...copyOptions,
|
|
99
|
+
relativePrefix: relativePath
|
|
100
|
+
});
|
|
101
|
+
if (nestedResult.isErr()) {
|
|
102
|
+
return nestedResult;
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (!sourceStat.isFile()) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const outputFilename = getOutputFilename(entry);
|
|
110
|
+
const targetPath = join(targetDir, outputFilename);
|
|
111
|
+
const targetExists = existsSync(targetPath);
|
|
112
|
+
const canOverlay = allowOverwrite && (!targetExists || Boolean(copyOptions?.overwritablePaths?.has(targetPath)));
|
|
113
|
+
if (targetExists && !options.force && !canOverlay) {
|
|
114
|
+
if (options.collector) {
|
|
115
|
+
options.collector.add({
|
|
116
|
+
type: "file-skip",
|
|
117
|
+
path: targetPath,
|
|
118
|
+
reason: "exists"
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
return Result.err(new ScaffoldError(`File '${targetPath}' already exists. Use --force to overwrite.`));
|
|
123
|
+
}
|
|
124
|
+
if (options.collector) {
|
|
125
|
+
if (targetExists) {
|
|
126
|
+
options.collector.add({
|
|
127
|
+
type: "file-overwrite",
|
|
128
|
+
path: targetPath,
|
|
129
|
+
source: "preset"
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
options.collector.add({
|
|
133
|
+
type: "file-create",
|
|
134
|
+
path: targetPath,
|
|
135
|
+
source: "preset"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
copyOptions?.writtenPaths?.add(targetPath);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isBinaryFile(outputFilename)) {
|
|
142
|
+
const buffer = readFileSync(sourcePath);
|
|
143
|
+
writeFileSync(targetPath, buffer);
|
|
144
|
+
copyOptions?.writtenPaths?.add(targetPath);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const content = readFileSync(sourcePath, "utf-8");
|
|
148
|
+
const processedContent = replacePlaceholders(content, values);
|
|
149
|
+
writeFileSync(targetPath, processedContent, "utf-8");
|
|
150
|
+
copyOptions?.writtenPaths?.add(targetPath);
|
|
151
|
+
}
|
|
152
|
+
return Result.ok(undefined);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
155
|
+
return Result.err(new ScaffoldError(`Failed to copy preset files: ${message}`));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export { getPresetsBaseDir, getOutputFilename, isBinaryFile, replacePlaceholders, copyPresetFiles };
|