@forge-ts/cli 0.16.0 → 0.18.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/{chunk-DV33Y4E2.js → chunk-JVI2NAXX.js} +106 -38
- package/dist/chunk-JVI2NAXX.js.map +1 -0
- package/dist/index.d.ts +11 -3
- package/dist/index.js +278 -57
- package/dist/index.js.map +1 -1
- package/dist/{init-project-5AWZ2LAI.js → init-project-6CWF4CCX.js} +2 -2
- package/package.json +6 -6
- package/dist/chunk-DV33Y4E2.js.map +0 -1
- /package/dist/{init-project-5AWZ2LAI.js.map → init-project-6CWF4CCX.js.map} +0 -0
|
@@ -8,32 +8,73 @@ import {
|
|
|
8
8
|
} from "./chunk-ZFFY4AQX.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/init-project.ts
|
|
11
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
12
|
+
import { mkdir, writeFile as writeFile2 } from "fs/promises";
|
|
13
|
+
import { join as join2 } from "path";
|
|
14
|
+
import { defineCommand } from "citty";
|
|
15
|
+
|
|
16
|
+
// src/pkg-json.ts
|
|
11
17
|
import { existsSync, readFileSync } from "fs";
|
|
12
|
-
import {
|
|
18
|
+
import { writeFile } from "fs/promises";
|
|
13
19
|
import { join } from "path";
|
|
14
|
-
|
|
20
|
+
function readPkgJson(rootDir) {
|
|
21
|
+
const pkgPath = join(rootDir, "package.json");
|
|
22
|
+
if (!existsSync(pkgPath)) return null;
|
|
23
|
+
try {
|
|
24
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
25
|
+
const obj = JSON.parse(raw);
|
|
26
|
+
const match = raw.match(/\n(\s+)"/);
|
|
27
|
+
const indent = match ? match[1] : " ";
|
|
28
|
+
const trailingNewline = raw.endsWith("\n");
|
|
29
|
+
return { path: pkgPath, raw, obj, indent, trailingNewline };
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function serializePkgJson(pkg) {
|
|
35
|
+
return JSON.stringify(pkg.obj, null, pkg.indent) + (pkg.trailingNewline ? "\n" : "");
|
|
36
|
+
}
|
|
37
|
+
async function writePkgJson(pkg) {
|
|
38
|
+
await writeFile(pkg.path, serializePkgJson(pkg), "utf8");
|
|
39
|
+
}
|
|
40
|
+
function addScripts(pkg, scripts) {
|
|
41
|
+
const existing = pkg.obj.scripts ?? {};
|
|
42
|
+
const added = [];
|
|
43
|
+
for (const [key, value] of Object.entries(scripts)) {
|
|
44
|
+
if (!(key in existing)) {
|
|
45
|
+
existing[key] = value;
|
|
46
|
+
added.push(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (added.length > 0) {
|
|
50
|
+
pkg.obj.scripts = existing;
|
|
51
|
+
}
|
|
52
|
+
return added;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/commands/init-project.ts
|
|
15
56
|
function readJsonSafe(filePath) {
|
|
16
|
-
if (!
|
|
57
|
+
if (!existsSync2(filePath)) {
|
|
17
58
|
return null;
|
|
18
59
|
}
|
|
19
60
|
try {
|
|
20
|
-
const raw =
|
|
61
|
+
const raw = readFileSync2(filePath, "utf8");
|
|
21
62
|
return JSON.parse(raw);
|
|
22
63
|
} catch {
|
|
23
64
|
return null;
|
|
24
65
|
}
|
|
25
66
|
}
|
|
26
67
|
function detectEnvironment(rootDir) {
|
|
27
|
-
const packageJsonPath =
|
|
28
|
-
const tsconfigPath =
|
|
29
|
-
const biomePath =
|
|
30
|
-
const biomecPath =
|
|
31
|
-
const pnpmWorkspacePath =
|
|
32
|
-
const huskyDir =
|
|
33
|
-
const lefthookYml =
|
|
34
|
-
const packageJsonExists =
|
|
35
|
-
const tsconfigExists =
|
|
36
|
-
const biomeDetected =
|
|
68
|
+
const packageJsonPath = join2(rootDir, "package.json");
|
|
69
|
+
const tsconfigPath = join2(rootDir, "tsconfig.json");
|
|
70
|
+
const biomePath = join2(rootDir, "biome.json");
|
|
71
|
+
const biomecPath = join2(rootDir, "biome.jsonc");
|
|
72
|
+
const pnpmWorkspacePath = join2(rootDir, "pnpm-workspace.yaml");
|
|
73
|
+
const huskyDir = join2(rootDir, ".husky");
|
|
74
|
+
const lefthookYml = join2(rootDir, "lefthook.yml");
|
|
75
|
+
const packageJsonExists = existsSync2(packageJsonPath);
|
|
76
|
+
const tsconfigExists = existsSync2(tsconfigPath);
|
|
77
|
+
const biomeDetected = existsSync2(biomePath) || existsSync2(biomecPath);
|
|
37
78
|
let typescriptVersion = null;
|
|
38
79
|
if (packageJsonExists) {
|
|
39
80
|
const pkg = readJsonSafe(packageJsonPath);
|
|
@@ -43,9 +84,9 @@ function detectEnvironment(rootDir) {
|
|
|
43
84
|
}
|
|
44
85
|
}
|
|
45
86
|
let hookManager = "none";
|
|
46
|
-
if (
|
|
87
|
+
if (existsSync2(huskyDir)) {
|
|
47
88
|
hookManager = "husky";
|
|
48
|
-
} else if (
|
|
89
|
+
} else if (existsSync2(lefthookYml)) {
|
|
49
90
|
hookManager = "lefthook";
|
|
50
91
|
} else if (packageJsonExists) {
|
|
51
92
|
const pkg = readJsonSafe(packageJsonPath);
|
|
@@ -60,7 +101,7 @@ function detectEnvironment(rootDir) {
|
|
|
60
101
|
}
|
|
61
102
|
let monorepo = false;
|
|
62
103
|
let monorepoType = null;
|
|
63
|
-
if (
|
|
104
|
+
if (existsSync2(pnpmWorkspacePath)) {
|
|
64
105
|
monorepo = true;
|
|
65
106
|
monorepoType = "pnpm";
|
|
66
107
|
} else if (packageJsonExists) {
|
|
@@ -84,18 +125,8 @@ var DEFAULT_CONFIG_CONTENT = `import { defineConfig } from "@forge-ts/core";
|
|
|
84
125
|
|
|
85
126
|
export default defineConfig({
|
|
86
127
|
rootDir: ".",
|
|
87
|
-
tsconfig: "tsconfig.json",
|
|
88
128
|
outDir: "docs/generated",
|
|
89
|
-
enforce: {
|
|
90
|
-
enabled: true,
|
|
91
|
-
minVisibility: "public",
|
|
92
|
-
strict: false,
|
|
93
|
-
},
|
|
94
129
|
gen: {
|
|
95
|
-
enabled: true,
|
|
96
|
-
formats: ["mdx"],
|
|
97
|
-
llmsTxt: true,
|
|
98
|
-
readmeSync: false,
|
|
99
130
|
ssgTarget: "mintlify",
|
|
100
131
|
},
|
|
101
132
|
});
|
|
@@ -108,6 +139,13 @@ var DEFAULT_TSDOC_CONTENT = JSON.stringify(
|
|
|
108
139
|
null,
|
|
109
140
|
" "
|
|
110
141
|
);
|
|
142
|
+
var FORGE_SCRIPTS = {
|
|
143
|
+
"forge:check": "forge-ts check",
|
|
144
|
+
"forge:test": "forge-ts test",
|
|
145
|
+
"forge:build": "forge-ts build",
|
|
146
|
+
"forge:doctor": "forge-ts doctor",
|
|
147
|
+
prepublishOnly: "forge-ts prepublish"
|
|
148
|
+
};
|
|
111
149
|
async function runInitProject(args) {
|
|
112
150
|
const start = Date.now();
|
|
113
151
|
const rootDir = args.cwd ?? process.cwd();
|
|
@@ -130,7 +168,8 @@ async function runInitProject(args) {
|
|
|
130
168
|
skipped: [],
|
|
131
169
|
warnings: [],
|
|
132
170
|
environment,
|
|
133
|
-
nextSteps: []
|
|
171
|
+
nextSteps: [],
|
|
172
|
+
scriptsAdded: []
|
|
134
173
|
},
|
|
135
174
|
errors: [err],
|
|
136
175
|
duration: Date.now() - start
|
|
@@ -145,24 +184,42 @@ async function runInitProject(args) {
|
|
|
145
184
|
}
|
|
146
185
|
if (!environment.biomeDetected) {
|
|
147
186
|
}
|
|
148
|
-
const configPath =
|
|
149
|
-
if (
|
|
187
|
+
const configPath = join2(rootDir, "forge-ts.config.ts");
|
|
188
|
+
if (existsSync2(configPath)) {
|
|
150
189
|
skipped.push("forge-ts.config.ts");
|
|
151
190
|
} else {
|
|
152
191
|
await mkdir(rootDir, { recursive: true });
|
|
153
|
-
await
|
|
192
|
+
await writeFile2(configPath, DEFAULT_CONFIG_CONTENT, "utf8");
|
|
154
193
|
created.push("forge-ts.config.ts");
|
|
155
194
|
}
|
|
156
|
-
const tsdocPath =
|
|
157
|
-
if (
|
|
195
|
+
const tsdocPath = join2(rootDir, "tsdoc.json");
|
|
196
|
+
if (existsSync2(tsdocPath)) {
|
|
158
197
|
skipped.push("tsdoc.json");
|
|
159
198
|
} else {
|
|
160
|
-
await
|
|
199
|
+
await writeFile2(tsdocPath, `${DEFAULT_TSDOC_CONTENT}
|
|
161
200
|
`, "utf8");
|
|
162
201
|
created.push("tsdoc.json");
|
|
163
202
|
}
|
|
203
|
+
let scriptsAdded = [];
|
|
204
|
+
if (environment.packageJsonExists) {
|
|
205
|
+
const pkg2 = readPkgJson(rootDir);
|
|
206
|
+
if (pkg2) {
|
|
207
|
+
scriptsAdded = addScripts(pkg2, FORGE_SCRIPTS);
|
|
208
|
+
if (scriptsAdded.length > 0) {
|
|
209
|
+
try {
|
|
210
|
+
await writePkgJson(pkg2);
|
|
211
|
+
} catch {
|
|
212
|
+
warnings.push("package.json: failed to wire scripts \u2014 file may be malformed.");
|
|
213
|
+
cliWarnings.push({
|
|
214
|
+
code: "INIT_SCRIPTS_FAILED",
|
|
215
|
+
message: "package.json: failed to wire scripts \u2014 file may be malformed."
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
164
221
|
if (environment.tsconfigExists) {
|
|
165
|
-
const tsconfigPath =
|
|
222
|
+
const tsconfigPath = join2(rootDir, "tsconfig.json");
|
|
166
223
|
const tsconfig = readJsonSafe(tsconfigPath);
|
|
167
224
|
if (tsconfig) {
|
|
168
225
|
if (!tsconfig.compilerOptions || tsconfig.compilerOptions.strict !== true) {
|
|
@@ -174,7 +231,7 @@ async function runInitProject(args) {
|
|
|
174
231
|
}
|
|
175
232
|
}
|
|
176
233
|
}
|
|
177
|
-
const pkgPath =
|
|
234
|
+
const pkgPath = join2(rootDir, "package.json");
|
|
178
235
|
const pkg = readJsonSafe(pkgPath);
|
|
179
236
|
if (pkg) {
|
|
180
237
|
if (pkg.type !== "module") {
|
|
@@ -212,7 +269,8 @@ async function runInitProject(args) {
|
|
|
212
269
|
skipped,
|
|
213
270
|
warnings,
|
|
214
271
|
environment,
|
|
215
|
-
nextSteps
|
|
272
|
+
nextSteps,
|
|
273
|
+
scriptsAdded
|
|
216
274
|
};
|
|
217
275
|
return {
|
|
218
276
|
operation: "init",
|
|
@@ -242,6 +300,13 @@ function formatInitProjectHuman(result) {
|
|
|
242
300
|
lines.push(" Already exists (skipped):");
|
|
243
301
|
lines.push(" (none)");
|
|
244
302
|
}
|
|
303
|
+
if (result.scriptsAdded.length > 0) {
|
|
304
|
+
lines.push("");
|
|
305
|
+
lines.push(" Scripts added to package.json:");
|
|
306
|
+
for (const script of result.scriptsAdded) {
|
|
307
|
+
lines.push(` ${script}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
245
310
|
if (result.warnings.length > 0) {
|
|
246
311
|
lines.push("");
|
|
247
312
|
lines.push(" Warnings:");
|
|
@@ -326,8 +391,11 @@ var initProjectCommand = defineCommand({
|
|
|
326
391
|
});
|
|
327
392
|
|
|
328
393
|
export {
|
|
394
|
+
readPkgJson,
|
|
395
|
+
writePkgJson,
|
|
396
|
+
addScripts,
|
|
329
397
|
detectEnvironment,
|
|
330
398
|
runInitProject,
|
|
331
399
|
initProjectCommand
|
|
332
400
|
};
|
|
333
|
-
//# sourceMappingURL=chunk-
|
|
401
|
+
//# sourceMappingURL=chunk-JVI2NAXX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/init-project.ts","../src/pkg-json.ts"],"sourcesContent":["/**\n * `forge-ts init` command — full project setup.\n *\n * Detects the project environment, writes default config files, validates\n * tsconfig/package.json, and prints a summary with next steps.\n *\n * @packageDocumentation\n * @internal\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { defineCommand } from \"citty\";\nimport { forgeLogger } from \"../forge-logger.js\";\nimport {\n\ttype CommandOutput,\n\temitResult,\n\ttype ForgeCliError,\n\ttype ForgeCliWarning,\n\ttype OutputFlags,\n\tresolveExitCode,\n} from \"../output.js\";\nimport { addScripts, readPkgJson, writePkgJson } from \"../pkg-json.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Detected project environment from Step 1 of the init flow.\n *\n * @public\n */\nexport interface InitProjectEnvironment {\n\t/** Whether package.json exists. */\n\tpackageJsonExists: boolean;\n\t/** Whether tsconfig.json exists. */\n\ttsconfigExists: boolean;\n\t/** Whether biome.json or biome.jsonc exists. */\n\tbiomeDetected: boolean;\n\t/** TypeScript version from dependencies, or null if not found. */\n\ttypescriptVersion: string | null;\n\t/** Detected hook manager. */\n\thookManager: \"husky\" | \"lefthook\" | \"none\";\n\t/** Whether the project is a monorepo. */\n\tmonorepo: boolean;\n\t/** Monorepo type if detected. */\n\tmonorepoType: \"pnpm\" | \"npm/yarn\" | null;\n}\n\n/**\n * Result of the `init` (project setup) command.\n *\n * @example\n * ```typescript\n * import { runInitProject } from \"@forge-ts/cli/commands/init-project\";\n * const output = await runInitProject({ cwd: process.cwd() });\n * console.log(output.data.created); // list of created files\n * ```\n * @public\n */\nexport interface InitProjectResult {\n\t/** Whether the init succeeded. */\n\tsuccess: boolean;\n\t/** Files that were created. */\n\tcreated: string[];\n\t/** Files that already existed and were skipped. */\n\tskipped: string[];\n\t/** Warning messages collected during init. */\n\twarnings: string[];\n\t/** Detected project environment. */\n\tenvironment: InitProjectEnvironment;\n\t/** Next steps for the user. */\n\tnextSteps: string[];\n\t/** Scripts that were added to package.json (empty if none were added). */\n\tscriptsAdded: string[];\n}\n\n/**\n * Arguments for the `init` (project setup) command.\n * @internal\n */\nexport interface InitProjectArgs {\n\t/** Project root directory (default: cwd). */\n\tcwd?: string;\n\t/** MVI verbosity level for structured output. */\n\tmvi?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Reads and parses a package.json file.\n * @internal\n */\ninterface PackageJsonShape {\n\ttype?: string;\n\tengines?: { node?: string };\n\tdependencies?: Record<string, string>;\n\tdevDependencies?: Record<string, string>;\n\tscripts?: Record<string, string>;\n\tworkspaces?: string[] | { packages: string[] };\n}\n\n/**\n * Safely reads and parses a JSON file.\n * @internal\n */\nfunction readJsonSafe<T>(filePath: string): T | null {\n\tif (!existsSync(filePath)) {\n\t\treturn null;\n\t}\n\ttry {\n\t\tconst raw = readFileSync(filePath, \"utf8\");\n\t\treturn JSON.parse(raw) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Environment detection\n// ---------------------------------------------------------------------------\n\n/**\n * Detects the project environment by checking for files and dependencies.\n *\n * @param rootDir - Absolute path to the project root.\n * @returns The detected environment.\n * @internal\n */\nexport function detectEnvironment(rootDir: string): InitProjectEnvironment {\n\tconst packageJsonPath = join(rootDir, \"package.json\");\n\tconst tsconfigPath = join(rootDir, \"tsconfig.json\");\n\tconst biomePath = join(rootDir, \"biome.json\");\n\tconst biomecPath = join(rootDir, \"biome.jsonc\");\n\tconst pnpmWorkspacePath = join(rootDir, \"pnpm-workspace.yaml\");\n\tconst huskyDir = join(rootDir, \".husky\");\n\tconst lefthookYml = join(rootDir, \"lefthook.yml\");\n\n\tconst packageJsonExists = existsSync(packageJsonPath);\n\tconst tsconfigExists = existsSync(tsconfigPath);\n\tconst biomeDetected = existsSync(biomePath) || existsSync(biomecPath);\n\n\t// TypeScript version detection\n\tlet typescriptVersion: string | null = null;\n\tif (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg) {\n\t\t\tconst tsVersion = pkg.devDependencies?.typescript ?? pkg.dependencies?.typescript ?? null;\n\t\t\ttypescriptVersion = tsVersion;\n\t\t}\n\t}\n\n\t// Hook manager detection\n\tlet hookManager: \"husky\" | \"lefthook\" | \"none\" = \"none\";\n\tif (existsSync(huskyDir)) {\n\t\thookManager = \"husky\";\n\t} else if (existsSync(lefthookYml)) {\n\t\thookManager = \"lefthook\";\n\t} else if (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg) {\n\t\t\tconst allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\t\t\tif (\"husky\" in allDeps) {\n\t\t\t\thookManager = \"husky\";\n\t\t\t} else if (\"lefthook\" in allDeps) {\n\t\t\t\thookManager = \"lefthook\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Monorepo detection\n\tlet monorepo = false;\n\tlet monorepoType: \"pnpm\" | \"npm/yarn\" | null = null;\n\tif (existsSync(pnpmWorkspacePath)) {\n\t\tmonorepo = true;\n\t\tmonorepoType = \"pnpm\";\n\t} else if (packageJsonExists) {\n\t\tconst pkg = readJsonSafe<PackageJsonShape>(packageJsonPath);\n\t\tif (pkg?.workspaces) {\n\t\t\tmonorepo = true;\n\t\t\tmonorepoType = \"npm/yarn\";\n\t\t}\n\t}\n\n\treturn {\n\t\tpackageJsonExists,\n\t\ttsconfigExists,\n\t\tbiomeDetected,\n\t\ttypescriptVersion,\n\t\thookManager,\n\t\tmonorepo,\n\t\tmonorepoType,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Config file content\n// ---------------------------------------------------------------------------\n\n/**\n * Default forge-ts.config.ts content for new projects.\n *\n * Only overrides that differ from built-in defaults are included.\n * The full defaults (enforce rules, doctest, etc.) are merged\n * automatically by `loadConfig()` → `mergeWithDefaults()`.\n * @internal\n */\nconst DEFAULT_CONFIG_CONTENT = `import { defineConfig } from \"@forge-ts/core\";\n\nexport default defineConfig({\n rootDir: \".\",\n outDir: \"docs/generated\",\n gen: {\n ssgTarget: \"mintlify\",\n },\n});\n`;\n\n/**\n * Default tsdoc.json content.\n * @internal\n */\nconst DEFAULT_TSDOC_CONTENT = JSON.stringify(\n\t{\n\t\t$schema: \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n\t\textends: [\"@forge-ts/core/tsdoc-preset/tsdoc.json\"],\n\t},\n\tnull,\n\t\"\\t\",\n);\n\n/**\n * Default npm scripts wired by `forge-ts init`.\n *\n * Each entry is only added when the key does **not** already exist in\n * the user's `package.json`, making the operation idempotent.\n * @internal\n */\nconst FORGE_SCRIPTS: Record<string, string> = {\n\t\"forge:check\": \"forge-ts check\",\n\t\"forge:test\": \"forge-ts test\",\n\t\"forge:build\": \"forge-ts build\",\n\t\"forge:doctor\": \"forge-ts doctor\",\n\tprepublishOnly: \"forge-ts prepublish\",\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Runs the full project init flow.\n *\n * Steps:\n * 1. Detect project environment\n * 2. Write forge-ts.config.ts (if not exists)\n * 3. Write tsdoc.json (if not exists)\n * 4. Wire package.json scripts (idempotent)\n * 5. Validate tsconfig.json strictness\n * 6. Validate package.json\n * 7. Report summary\n *\n * @param args - CLI arguments for the init command.\n * @returns A typed `CommandOutput<InitProjectResult>`.\n * @example\n * ```typescript\n * import { runInitProject } from \"@forge-ts/cli/commands/init-project\";\n * const output = await runInitProject({ cwd: process.cwd() });\n * console.log(output.data.created); // [\"forge-ts.config.ts\", \"tsdoc.json\"]\n * ```\n * @public\n */\nexport async function runInitProject(\n\targs: InitProjectArgs,\n): Promise<CommandOutput<InitProjectResult>> {\n\tconst start = Date.now();\n\tconst rootDir = args.cwd ?? process.cwd();\n\n\tconst created: string[] = [];\n\tconst skipped: string[] = [];\n\tconst warnings: string[] = [];\n\tconst cliWarnings: ForgeCliWarning[] = [];\n\n\t// -----------------------------------------------------------------------\n\t// Step 1: Detect project environment\n\t// -----------------------------------------------------------------------\n\n\tconst environment = detectEnvironment(rootDir);\n\n\tif (!environment.packageJsonExists) {\n\t\tconst err: ForgeCliError = {\n\t\t\tcode: \"INIT_NO_PACKAGE_JSON\",\n\t\t\tmessage: \"package.json not found. Run `npm init` or `pnpm init` first.\",\n\t\t};\n\t\treturn {\n\t\t\toperation: \"init\",\n\t\t\tsuccess: false,\n\t\t\tdata: {\n\t\t\t\tsuccess: false,\n\t\t\t\tcreated: [],\n\t\t\t\tskipped: [],\n\t\t\t\twarnings: [],\n\t\t\t\tenvironment,\n\t\t\t\tnextSteps: [],\n\t\t\t\tscriptsAdded: [],\n\t\t\t},\n\t\t\terrors: [err],\n\t\t\tduration: Date.now() - start,\n\t\t};\n\t}\n\n\tif (!environment.tsconfigExists) {\n\t\twarnings.push(\"tsconfig.json not found. forge-ts requires TypeScript.\");\n\t\tcliWarnings.push({\n\t\t\tcode: \"INIT_NO_TSCONFIG\",\n\t\t\tmessage: \"tsconfig.json not found. forge-ts requires TypeScript.\",\n\t\t});\n\t}\n\n\tif (!environment.biomeDetected) {\n\t\t// Informational — not a warning\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 2: Write forge-ts.config.ts\n\t// -----------------------------------------------------------------------\n\n\tconst configPath = join(rootDir, \"forge-ts.config.ts\");\n\tif (existsSync(configPath)) {\n\t\tskipped.push(\"forge-ts.config.ts\");\n\t} else {\n\t\tawait mkdir(rootDir, { recursive: true });\n\t\tawait writeFile(configPath, DEFAULT_CONFIG_CONTENT, \"utf8\");\n\t\tcreated.push(\"forge-ts.config.ts\");\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 3: Write tsdoc.json\n\t// -----------------------------------------------------------------------\n\n\tconst tsdocPath = join(rootDir, \"tsdoc.json\");\n\tif (existsSync(tsdocPath)) {\n\t\tskipped.push(\"tsdoc.json\");\n\t} else {\n\t\tawait writeFile(tsdocPath, `${DEFAULT_TSDOC_CONTENT}\\n`, \"utf8\");\n\t\tcreated.push(\"tsdoc.json\");\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 4: Wire package.json scripts (idempotent)\n\t// -----------------------------------------------------------------------\n\n\tlet scriptsAdded: string[] = [];\n\tif (environment.packageJsonExists) {\n\t\tconst pkg = readPkgJson(rootDir);\n\t\tif (pkg) {\n\t\t\tscriptsAdded = addScripts(pkg, FORGE_SCRIPTS);\n\t\t\tif (scriptsAdded.length > 0) {\n\t\t\t\ttry {\n\t\t\t\t\tawait writePkgJson(pkg);\n\t\t\t\t} catch {\n\t\t\t\t\twarnings.push(\"package.json: failed to wire scripts — file may be malformed.\");\n\t\t\t\t\tcliWarnings.push({\n\t\t\t\t\t\tcode: \"INIT_SCRIPTS_FAILED\",\n\t\t\t\t\t\tmessage: \"package.json: failed to wire scripts — file may be malformed.\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 5: Validate tsconfig.json strictness\n\t// -----------------------------------------------------------------------\n\n\tif (environment.tsconfigExists) {\n\t\tconst tsconfigPath = join(rootDir, \"tsconfig.json\");\n\t\tconst tsconfig = readJsonSafe<{\n\t\t\tcompilerOptions?: { strict?: boolean };\n\t\t}>(tsconfigPath);\n\n\t\tif (tsconfig) {\n\t\t\tif (!tsconfig.compilerOptions || tsconfig.compilerOptions.strict !== true) {\n\t\t\t\twarnings.push(\"tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode.\");\n\t\t\t\tcliWarnings.push({\n\t\t\t\t\tcode: \"INIT_TSCONFIG_NOT_STRICT\",\n\t\t\t\t\tmessage: \"tsconfig.json: 'strict' is not enabled. forge-ts recommends strict mode.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 6: Validate package.json\n\t// -----------------------------------------------------------------------\n\n\tconst pkgPath = join(rootDir, \"package.json\");\n\tconst pkg = readJsonSafe<PackageJsonShape>(pkgPath);\n\n\tif (pkg) {\n\t\tif (pkg.type !== \"module\") {\n\t\t\twarnings.push('package.json: missing \"type\": \"module\". forge-ts uses ESM.');\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_NO_ESM\",\n\t\t\t\tmessage: 'package.json: missing \"type\": \"module\". forge-ts uses ESM.',\n\t\t\t});\n\t\t}\n\n\t\tif (!pkg.engines?.node) {\n\t\t\twarnings.push(\"package.json: missing engines.node field.\");\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_NO_ENGINES\",\n\t\t\t\tmessage: \"package.json: missing engines.node field.\",\n\t\t\t});\n\t\t}\n\n\t\tconst allDeps = { ...pkg.dependencies, ...pkg.devDependencies };\n\t\tif (!(\"@forge-ts/cli\" in allDeps)) {\n\t\t\twarnings.push(\"package.json: @forge-ts/cli not in devDependencies (running via npx?).\");\n\t\t\tcliWarnings.push({\n\t\t\t\tcode: \"INIT_CLI_NOT_INSTALLED\",\n\t\t\t\tmessage: \"package.json: @forge-ts/cli not in devDependencies (running via npx?).\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 7: Build result\n\t// -----------------------------------------------------------------------\n\n\tconst nextSteps: string[] = [\n\t\t\"Run: forge-ts check (lint TSDoc coverage)\",\n\t\t\"Run: forge-ts init docs (scaffold documentation site)\",\n\t\t\"Run: forge-ts init hooks (scaffold pre-commit hooks)\",\n\t\t\"Run: forge-ts lock (lock config to prevent drift)\",\n\t];\n\n\tconst data: InitProjectResult = {\n\t\tsuccess: true,\n\t\tcreated,\n\t\tskipped,\n\t\twarnings,\n\t\tenvironment,\n\t\tnextSteps,\n\t\tscriptsAdded,\n\t};\n\n\treturn {\n\t\toperation: \"init\",\n\t\tsuccess: true,\n\t\tdata,\n\t\twarnings: cliWarnings.length > 0 ? cliWarnings : undefined,\n\t\tduration: Date.now() - start,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Human formatter\n// ---------------------------------------------------------------------------\n\n/**\n * Formats an InitProjectResult as human-readable text.\n * @internal\n */\nfunction formatInitProjectHuman(result: InitProjectResult): string {\n\tconst lines: string[] = [];\n\n\tlines.push(\"\\nforge-ts init: project setup complete\\n\");\n\n\t// Created files\n\tif (result.created.length > 0) {\n\t\tlines.push(\" Created:\");\n\t\tfor (const file of result.created) {\n\t\t\tlines.push(` ${file}`);\n\t\t}\n\t}\n\n\t// Skipped files\n\tif (result.skipped.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Already exists (skipped):\");\n\t\tfor (const file of result.skipped) {\n\t\t\tlines.push(` ${file}`);\n\t\t}\n\t} else if (result.created.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Already exists (skipped):\");\n\t\tlines.push(\" (none)\");\n\t}\n\n\t// Scripts added\n\tif (result.scriptsAdded.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Scripts added to package.json:\");\n\t\tfor (const script of result.scriptsAdded) {\n\t\t\tlines.push(` ${script}`);\n\t\t}\n\t}\n\n\t// Warnings\n\tif (result.warnings.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Warnings:\");\n\t\tfor (const warning of result.warnings) {\n\t\t\tlines.push(` ${warning}`);\n\t\t}\n\t}\n\n\t// Environment\n\tconst env = result.environment;\n\tlines.push(\"\");\n\tlines.push(\" Environment:\");\n\tlines.push(` TypeScript: ${env.typescriptVersion ?? \"not detected\"}`);\n\tlines.push(` Biome: ${env.biomeDetected ? \"detected\" : \"not detected\"}`);\n\n\tconst hookLabel = env.hookManager === \"none\" ? \"not detected\" : `${env.hookManager} detected`;\n\tlines.push(` Git hooks: ${hookLabel}`);\n\n\tif (env.monorepo) {\n\t\tlines.push(\n\t\t\t` Monorepo: ${env.monorepoType === \"pnpm\" ? \"pnpm workspaces\" : \"npm/yarn workspaces\"}`,\n\t\t);\n\t} else {\n\t\tlines.push(\" Monorepo: no\");\n\t}\n\n\t// Next steps\n\tif (result.nextSteps.length > 0) {\n\t\tlines.push(\"\");\n\t\tlines.push(\" Next steps:\");\n\t\tfor (const [idx, step] of result.nextSteps.entries()) {\n\t\t\tlines.push(` ${idx + 1}. ${step}`);\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Citty command definition\n// ---------------------------------------------------------------------------\n\n/**\n * Citty command definition for `forge-ts init` (bare — full project setup).\n *\n * Detects the project environment, writes default configuration files,\n * validates tsconfig/package.json, and reports a summary.\n *\n * @example\n * ```typescript\n * import { initProjectCommand } from \"@forge-ts/cli/commands/init-project\";\n * // Registered as the default handler for `forge-ts init`\n * ```\n * @public\n */\nexport const initProjectCommand = defineCommand({\n\tmeta: {\n\t\tname: \"init\",\n\t\tdescription: \"Full project setup for forge-ts\",\n\t},\n\targs: {\n\t\tcwd: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"Project root directory\",\n\t\t},\n\t\tjson: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Output as LAFS JSON envelope\",\n\t\t\tdefault: false,\n\t\t},\n\t\thuman: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Output as formatted text\",\n\t\t\tdefault: false,\n\t\t},\n\t\tquiet: {\n\t\t\ttype: \"boolean\",\n\t\t\tdescription: \"Suppress non-essential output\",\n\t\t\tdefault: false,\n\t\t},\n\t\tmvi: {\n\t\t\ttype: \"string\",\n\t\t\tdescription: \"MVI verbosity level: minimal, standard, full\",\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst output = await runInitProject({\n\t\t\tcwd: args.cwd,\n\t\t\tmvi: args.mvi,\n\t\t});\n\n\t\tconst flags: OutputFlags = {\n\t\t\tjson: args.json,\n\t\t\thuman: args.human,\n\t\t\tquiet: args.quiet,\n\t\t\tmvi: args.mvi,\n\t\t};\n\n\t\temitResult(output, flags, (data, cmd) => {\n\t\t\tif (!cmd.success) {\n\t\t\t\tconst msg = cmd.errors?.[0]?.message ?? \"Init failed\";\n\t\t\t\tforgeLogger.error(msg);\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn formatInitProjectHuman(data);\n\t\t});\n\n\t\tprocess.exit(resolveExitCode(output));\n\t},\n});\n","/**\n * Shared utilities for idempotent package.json read-modify-write operations.\n *\n * Every command that touches package.json MUST use these helpers to ensure:\n * - Existing content is never lost\n * - JSON formatting (indent style, trailing newline) is preserved\n * - Scripts are only added when the key doesn't already exist\n *\n * @packageDocumentation\n * @internal\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Parsed package.json with formatting metadata for lossless round-tripping.\n * @internal\n */\nexport interface PkgJson {\n\t/** Absolute path to the file. */\n\tpath: string;\n\t/** Raw file content as read from disk. */\n\traw: string;\n\t/** Parsed JSON object. */\n\tobj: Record<string, unknown>;\n\t/** Detected indent string (tabs or spaces). */\n\tindent: string;\n\t/** Whether the original file ended with a newline. */\n\ttrailingNewline: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Read\n// ---------------------------------------------------------------------------\n\n/**\n * Read and parse package.json from a project root.\n *\n * Detects indent style and trailing newline for lossless round-tripping.\n * Returns `null` if the file doesn't exist or can't be parsed.\n *\n * @param rootDir - Absolute path to the project root.\n * @returns Parsed package.json with formatting metadata, or null.\n * @internal\n */\nexport function readPkgJson(rootDir: string): PkgJson | null {\n\tconst pkgPath = join(rootDir, \"package.json\");\n\tif (!existsSync(pkgPath)) return null;\n\ttry {\n\t\tconst raw = readFileSync(pkgPath, \"utf8\");\n\t\tconst obj = JSON.parse(raw) as Record<string, unknown>;\n\t\tconst match = raw.match(/\\n(\\s+)\"/);\n\t\tconst indent = match ? match[1] : \" \";\n\t\tconst trailingNewline = raw.endsWith(\"\\n\");\n\t\treturn { path: pkgPath, raw, obj, indent, trailingNewline };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Write\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a package.json object preserving original formatting.\n *\n * @param pkg - The parsed package.json with formatting metadata.\n * @returns Formatted JSON string ready to write to disk.\n * @internal\n */\nexport function serializePkgJson(pkg: PkgJson): string {\n\treturn JSON.stringify(pkg.obj, null, pkg.indent) + (pkg.trailingNewline ? \"\\n\" : \"\");\n}\n\n/**\n * Write a modified package.json back to disk, preserving formatting.\n *\n * @param pkg - The parsed and modified package.json.\n * @internal\n */\nexport async function writePkgJson(pkg: PkgJson): Promise<void> {\n\tawait writeFile(pkg.path, serializePkgJson(pkg), \"utf8\");\n}\n\n// ---------------------------------------------------------------------------\n// Script helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Add scripts to package.json idempotently.\n *\n * Only adds scripts where the key doesn't already exist.\n * Never overwrites existing script values. Returns the list of keys added.\n *\n * @param pkg - The parsed package.json to modify (mutated in place).\n * @param scripts - Map of script key to command value.\n * @returns Array of script keys that were added (empty if all already existed).\n * @internal\n */\nexport function addScripts(pkg: PkgJson, scripts: Record<string, string>): string[] {\n\tconst existing = (pkg.obj.scripts ?? {}) as Record<string, string>;\n\tconst added: string[] = [];\n\n\tfor (const [key, value] of Object.entries(scripts)) {\n\t\tif (!(key in existing)) {\n\t\t\texisting[key] = value;\n\t\t\tadded.push(key);\n\t\t}\n\t}\n\n\tif (added.length > 0) {\n\t\tpkg.obj.scripts = existing;\n\t}\n\n\treturn added;\n}\n"],"mappings":"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","names":["existsSync","readFileSync","writeFile","join","existsSync","readFileSync","join","writeFile","pkg"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -493,6 +493,11 @@ declare const checkCommand: citty.CommandDef<{
|
|
|
493
493
|
readonly type: "string";
|
|
494
494
|
readonly description: "Filter by file path (substring match)";
|
|
495
495
|
};
|
|
496
|
+
readonly staged: {
|
|
497
|
+
readonly type: "boolean";
|
|
498
|
+
readonly description: "Only check symbols from git-staged .ts/.tsx files";
|
|
499
|
+
readonly default: false;
|
|
500
|
+
};
|
|
496
501
|
readonly limit: {
|
|
497
502
|
readonly type: "string";
|
|
498
503
|
readonly description: "Max file groups in output (default: 20)";
|
|
@@ -940,6 +945,8 @@ interface InitProjectResult {
|
|
|
940
945
|
environment: InitProjectEnvironment;
|
|
941
946
|
/** Next steps for the user. */
|
|
942
947
|
nextSteps: string[];
|
|
948
|
+
/** Scripts that were added to package.json (empty if none were added). */
|
|
949
|
+
scriptsAdded: string[];
|
|
943
950
|
}
|
|
944
951
|
/**
|
|
945
952
|
* Arguments for the `init` (project setup) command.
|
|
@@ -958,9 +965,10 @@ interface InitProjectArgs {
|
|
|
958
965
|
* 1. Detect project environment
|
|
959
966
|
* 2. Write forge-ts.config.ts (if not exists)
|
|
960
967
|
* 3. Write tsdoc.json (if not exists)
|
|
961
|
-
* 4.
|
|
962
|
-
* 5. Validate
|
|
963
|
-
* 6.
|
|
968
|
+
* 4. Wire package.json scripts (idempotent)
|
|
969
|
+
* 5. Validate tsconfig.json strictness
|
|
970
|
+
* 6. Validate package.json
|
|
971
|
+
* 7. Report summary
|
|
964
972
|
*
|
|
965
973
|
* @param args - CLI arguments for the init command.
|
|
966
974
|
* @returns A typed `CommandOutput<InitProjectResult>`.
|