@mono-labs/cli 0.0.206 → 0.0.208
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/project/build-mono-readme.js +338 -115
- package/package.json +1 -1
- package/src/project/build-mono-readme.ts +466 -208
|
@@ -1,36 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// scripts/generate-readme.ts
|
|
3
|
-
// Node >= 18 recommended
|
|
4
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
4
|
};
|
|
7
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
// scripts/generate-readme.mjs
|
|
7
|
+
// Node >= 18 recommended
|
|
8
8
|
const node_fs_1 = require("node:fs");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
10
|
const generate_docs_js_1 = require("./generate-docs.js");
|
|
11
|
-
/* -------------------------------------------------------------------------- */
|
|
12
|
-
/* Path helpers */
|
|
13
|
-
/* -------------------------------------------------------------------------- */
|
|
14
|
-
// Always use the working directory as the root for all file actions
|
|
15
11
|
const REPO_ROOT = node_path_1.default.resolve(process.cwd());
|
|
16
12
|
const MONO_DIR = node_path_1.default.join(REPO_ROOT, '.mono');
|
|
17
13
|
const ROOT_PKG_JSON = node_path_1.default.join(REPO_ROOT, 'package.json');
|
|
18
14
|
const OUTPUT_PATH = node_path_1.default.join(REPO_ROOT, 'docs');
|
|
19
15
|
const OUTPUT_README = node_path_1.default.join(OUTPUT_PATH, 'command-line.md');
|
|
20
|
-
/* -------------------------------------------------------------------------- */
|
|
21
|
-
/* Utils */
|
|
22
|
-
/* -------------------------------------------------------------------------- */
|
|
23
16
|
async function ensureParentDir(filePath) {
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
const dir = node_path_1.default.dirname(filePath);
|
|
18
|
+
console.log(`[ensureParentDir] Ensuring directory:`, dir);
|
|
26
19
|
await node_fs_1.promises.mkdir(dir, { recursive: true });
|
|
27
20
|
}
|
|
21
|
+
// ---------- utils ----------
|
|
28
22
|
async function exists(p) {
|
|
29
23
|
try {
|
|
30
24
|
await node_fs_1.promises.access(p);
|
|
25
|
+
// Log existence check
|
|
26
|
+
console.log(`[exists] Path exists:`, p);
|
|
31
27
|
return true;
|
|
32
28
|
}
|
|
33
29
|
catch {
|
|
30
|
+
console.log(`[exists] Path does NOT exist:`, p);
|
|
34
31
|
return false;
|
|
35
32
|
}
|
|
36
33
|
}
|
|
@@ -41,110 +38,135 @@ function toPosix(p) {
|
|
|
41
38
|
return p.split(node_path_1.default.sep).join('/');
|
|
42
39
|
}
|
|
43
40
|
async function readJson(filePath) {
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
console.log(`[readJson] Reading JSON file:`, filePath);
|
|
42
|
+
const raw = await node_fs_1.promises.readFile(filePath, 'utf8');
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
console.log(`[readJson] Successfully parsed:`, filePath);
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`[readJson] Failed to parse JSON:`, filePath, err);
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
48
52
|
}
|
|
49
53
|
async function listDir(dir) {
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
54
|
+
console.log(`[listDir] Listing directory:`, dir);
|
|
55
|
+
const entries = await node_fs_1.promises.readdir(dir, { withFileTypes: true });
|
|
56
|
+
console.log(`[listDir] Found ${entries.length} entries in:`, dir);
|
|
57
|
+
return entries;
|
|
53
58
|
}
|
|
54
59
|
function normalizeWorkspacePatterns(workspacesField) {
|
|
55
60
|
if (Array.isArray(workspacesField))
|
|
56
61
|
return workspacesField;
|
|
57
62
|
if (isObject(workspacesField) &&
|
|
58
|
-
Array.isArray(workspacesField.packages))
|
|
63
|
+
Array.isArray(workspacesField.packages))
|
|
59
64
|
return workspacesField.packages;
|
|
60
|
-
}
|
|
61
65
|
return [];
|
|
62
66
|
}
|
|
63
|
-
function mdEscapeInline(
|
|
64
|
-
return String(
|
|
67
|
+
function mdEscapeInline(s) {
|
|
68
|
+
return String(s ?? '').replaceAll('`', '\`');
|
|
65
69
|
}
|
|
66
70
|
function indentLines(s, spaces = 2) {
|
|
67
71
|
const pad = ' '.repeat(spaces);
|
|
68
|
-
return s
|
|
72
|
+
return String(s ?? '')
|
|
69
73
|
.split('\n')
|
|
70
|
-
.map((
|
|
74
|
+
.map((l) => pad + l)
|
|
71
75
|
.join('\n');
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
/* Workspace glob pattern expansion */
|
|
75
|
-
/* -------------------------------------------------------------------------- */
|
|
77
|
+
// ---------- workspace glob matching (supports *, **, and plain segments) ----------
|
|
76
78
|
function matchSegment(patternSeg, name) {
|
|
77
79
|
if (patternSeg === '*')
|
|
78
80
|
return true;
|
|
79
81
|
if (!patternSeg.includes('*'))
|
|
80
82
|
return patternSeg === name;
|
|
81
83
|
const escaped = patternSeg.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
82
|
-
const regex = new RegExp(
|
|
84
|
+
const regex = new RegExp('^' + escaped.replaceAll('*', '.*') + '$');
|
|
83
85
|
return regex.test(name);
|
|
84
86
|
}
|
|
85
87
|
async function expandWorkspacePattern(root, pattern) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
return [
|
|
92
|
-
const seg =
|
|
88
|
+
console.log(`[expandWorkspacePattern] Expanding pattern:`, pattern, `from root:`, root);
|
|
89
|
+
const segs = toPosix(pattern).split('/').filter(Boolean);
|
|
90
|
+
async function expandFrom(dir, segIndex) {
|
|
91
|
+
console.log(`[expandFrom] Directory:`, dir, `Segment index:`, segIndex);
|
|
92
|
+
if (segIndex >= segs.length)
|
|
93
|
+
return [dir];
|
|
94
|
+
const seg = segs[segIndex];
|
|
95
|
+
console.log(`[expandFrom] Segment:`, seg);
|
|
93
96
|
if (seg === '**') {
|
|
94
97
|
const results = [];
|
|
95
|
-
results.push(...(await expandFrom(
|
|
98
|
+
results.push(...(await expandFrom(dir, segIndex + 1)));
|
|
96
99
|
const entries = await node_fs_1.promises
|
|
97
|
-
.readdir(
|
|
100
|
+
.readdir(dir, { withFileTypes: true })
|
|
98
101
|
.catch(() => []);
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
console.log(`[expandFrom] '**' entries in ${dir}:`, entries.map((e) => e.name));
|
|
103
|
+
for (const e of entries) {
|
|
104
|
+
if (!e.isDirectory())
|
|
101
105
|
continue;
|
|
102
|
-
|
|
106
|
+
console.log(`[expandFrom] Recursing into subdir:`, node_path_1.default.join(dir, e.name));
|
|
107
|
+
results.push(...(await expandFrom(node_path_1.default.join(dir, e.name), segIndex)));
|
|
103
108
|
}
|
|
104
109
|
return results;
|
|
105
110
|
}
|
|
106
111
|
const entries = await node_fs_1.promises
|
|
107
|
-
.readdir(
|
|
112
|
+
.readdir(dir, { withFileTypes: true })
|
|
108
113
|
.catch(() => []);
|
|
114
|
+
console.log(`[expandFrom] Entries in ${dir}:`, entries.map((e) => e.name));
|
|
109
115
|
const results = [];
|
|
110
|
-
for (const
|
|
111
|
-
if (!
|
|
116
|
+
for (const e of entries) {
|
|
117
|
+
if (!e.isDirectory())
|
|
112
118
|
continue;
|
|
113
|
-
if (!matchSegment(seg,
|
|
119
|
+
if (!matchSegment(seg, e.name))
|
|
114
120
|
continue;
|
|
115
|
-
|
|
121
|
+
console.log(`[expandFrom] Matched segment '${seg}' with directory:`, e.name);
|
|
122
|
+
results.push(...(await expandFrom(node_path_1.default.join(dir, e.name), segIndex + 1)));
|
|
116
123
|
}
|
|
117
124
|
return results;
|
|
118
125
|
}
|
|
119
126
|
const dirs = await expandFrom(root, 0);
|
|
127
|
+
console.log(`[expandWorkspacePattern] Expanded directories:`, dirs);
|
|
120
128
|
const pkgDirs = [];
|
|
121
129
|
for (const d of dirs) {
|
|
122
|
-
|
|
130
|
+
const pkgPath = node_path_1.default.join(d, 'package.json');
|
|
131
|
+
if (await exists(pkgPath)) {
|
|
132
|
+
console.log(`[expandWorkspacePattern] Found package.json:`, pkgPath);
|
|
123
133
|
pkgDirs.push(d);
|
|
124
134
|
}
|
|
135
|
+
else {
|
|
136
|
+
console.log(`[expandWorkspacePattern] No package.json in:`, d);
|
|
137
|
+
}
|
|
125
138
|
}
|
|
126
|
-
|
|
139
|
+
console.log(`[expandWorkspacePattern] Final package directories:`, pkgDirs);
|
|
140
|
+
return [...new Set(pkgDirs)];
|
|
127
141
|
}
|
|
128
|
-
async function findWorkspacePackageDirs(repoRoot,
|
|
142
|
+
async function findWorkspacePackageDirs(repoRoot, workspacePatterns) {
|
|
143
|
+
console.log(`[findWorkspacePackageDirs] repoRoot:`, repoRoot, `workspacePatterns:`, workspacePatterns);
|
|
129
144
|
const dirs = [];
|
|
130
|
-
for (const pat of
|
|
131
|
-
|
|
145
|
+
for (const pat of workspacePatterns) {
|
|
146
|
+
console.log(`[findWorkspacePackageDirs] Expanding pattern:`, pat);
|
|
147
|
+
const expanded = await expandWorkspacePattern(repoRoot, pat);
|
|
148
|
+
console.log(`[findWorkspacePackageDirs] Expanded dirs for pattern '${pat}':`, expanded);
|
|
149
|
+
dirs.push(...expanded);
|
|
132
150
|
}
|
|
133
|
-
|
|
151
|
+
const uniqueDirs = [...new Set(dirs)];
|
|
152
|
+
console.log(`[findWorkspacePackageDirs] Final unique package dirs:`, uniqueDirs);
|
|
153
|
+
return uniqueDirs;
|
|
134
154
|
}
|
|
135
|
-
|
|
136
|
-
/* .mono configuration */
|
|
137
|
-
/* -------------------------------------------------------------------------- */
|
|
155
|
+
// ---------- .mono parsing ----------
|
|
138
156
|
async function readMonoConfig() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (!(await exists(configPath)))
|
|
157
|
+
const configPath = node_path_1.default.join(MONO_DIR, 'config.json');
|
|
158
|
+
console.log(`[readMonoConfig] Looking for mono config at:`, configPath);
|
|
159
|
+
if (!(await exists(configPath))) {
|
|
160
|
+
console.log(`[readMonoConfig] No mono config found.`);
|
|
142
161
|
return null;
|
|
162
|
+
}
|
|
143
163
|
try {
|
|
144
164
|
const config = await readJson(configPath);
|
|
165
|
+
console.log(`[readMonoConfig] Loaded mono config.`);
|
|
145
166
|
return { path: configPath, config };
|
|
146
167
|
}
|
|
147
|
-
catch {
|
|
168
|
+
catch (err) {
|
|
169
|
+
console.error(`[readMonoConfig] Failed to load mono config:`, err);
|
|
148
170
|
return null;
|
|
149
171
|
}
|
|
150
172
|
}
|
|
@@ -152,44 +174,52 @@ function commandNameFromFile(filePath) {
|
|
|
152
174
|
return node_path_1.default.basename(filePath).replace(/\.json$/i, '');
|
|
153
175
|
}
|
|
154
176
|
async function readMonoCommands() {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
177
|
+
console.log(`[readMonoCommands] Reading mono commands from:`, MONO_DIR);
|
|
178
|
+
if (!(await exists(MONO_DIR))) {
|
|
179
|
+
console.log(`[readMonoCommands] Mono directory does not exist.`);
|
|
158
180
|
return [];
|
|
159
|
-
|
|
181
|
+
}
|
|
182
|
+
const entries = await listDir(MONO_DIR);
|
|
160
183
|
const jsonFiles = entries
|
|
161
|
-
.filter((e) => e.isFile() && e.name.endsWith('.json'))
|
|
162
|
-
.map((e) => node_path_1.default.join(
|
|
163
|
-
.filter((p) => node_path_1.default.basename(p) !== 'config.json');
|
|
184
|
+
.filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.json'))
|
|
185
|
+
.map((e) => node_path_1.default.join(MONO_DIR, e.name))
|
|
186
|
+
.filter((p) => node_path_1.default.basename(p).toLowerCase() !== 'config.json');
|
|
187
|
+
console.log(`[readMonoCommands] Found JSON files:`, jsonFiles);
|
|
164
188
|
const commands = [];
|
|
165
189
|
for (const file of jsonFiles) {
|
|
166
190
|
try {
|
|
167
|
-
|
|
191
|
+
console.log(`[readMonoCommands] Reading command file:`, file);
|
|
192
|
+
const j = await readJson(file);
|
|
168
193
|
commands.push({
|
|
169
194
|
name: commandNameFromFile(file),
|
|
170
195
|
file,
|
|
171
|
-
json,
|
|
196
|
+
json: j,
|
|
172
197
|
});
|
|
198
|
+
console.log(`[readMonoCommands] Successfully loaded command:`, commandNameFromFile(file));
|
|
173
199
|
}
|
|
174
|
-
catch {
|
|
175
|
-
|
|
200
|
+
catch (err) {
|
|
201
|
+
console.error(`[readMonoCommands] Failed to load command file:`, file, err);
|
|
202
|
+
// skip invalid json
|
|
176
203
|
}
|
|
177
204
|
}
|
|
178
|
-
|
|
205
|
+
commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
206
|
+
console.log(`[readMonoCommands] Final sorted commands:`, commands.map((c) => c.name));
|
|
207
|
+
return commands;
|
|
179
208
|
}
|
|
180
|
-
/* -------------------------------------------------------------------------- */
|
|
181
|
-
/* Options schema parsing */
|
|
182
|
-
/* -------------------------------------------------------------------------- */
|
|
183
209
|
function parseOptionsSchema(optionsObj) {
|
|
210
|
+
// New structure supports:
|
|
211
|
+
// - optionKey: { type: "string", default, options: [], allowAll, shortcut, description }
|
|
212
|
+
// - boolean toggle: { shortcut, description } (no type)
|
|
184
213
|
if (!isObject(optionsObj))
|
|
185
214
|
return [];
|
|
186
215
|
const entries = Object.entries(optionsObj).map(([key, raw]) => {
|
|
187
216
|
const o = isObject(raw) ? raw : {};
|
|
188
|
-
const hasType = typeof o.type === 'string' && o.type.length > 0;
|
|
217
|
+
const hasType = typeof o.type === 'string' && o.type.trim().length > 0;
|
|
218
|
+
const isBoolToggle = !hasType; // in your examples, booleans omit `type`
|
|
189
219
|
return {
|
|
190
220
|
key,
|
|
191
|
-
kind:
|
|
192
|
-
type: hasType ? o.type : 'boolean',
|
|
221
|
+
kind: isBoolToggle ? 'boolean' : 'value',
|
|
222
|
+
type: hasType ? String(o.type) : 'boolean',
|
|
193
223
|
description: typeof o.description === 'string' ? o.description : '',
|
|
194
224
|
shortcut: typeof o.shortcut === 'string' ? o.shortcut : '',
|
|
195
225
|
default: o.default,
|
|
@@ -197,81 +227,274 @@ function parseOptionsSchema(optionsObj) {
|
|
|
197
227
|
allowAll: o.allowAll === true,
|
|
198
228
|
};
|
|
199
229
|
});
|
|
200
|
-
|
|
230
|
+
entries.sort((a, b) => a.key.localeCompare(b.key));
|
|
231
|
+
return entries;
|
|
201
232
|
}
|
|
202
|
-
/* -------------------------------------------------------------------------- */
|
|
203
|
-
/* Formatting */
|
|
204
|
-
/* -------------------------------------------------------------------------- */
|
|
205
233
|
function buildUsageExample(commandName, cmdJson, options) {
|
|
206
|
-
const arg = cmdJson
|
|
234
|
+
const arg = cmdJson?.argument;
|
|
207
235
|
const hasArg = isObject(arg);
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
parts.push(`<${commandName}-arg>`);
|
|
236
|
+
const argToken = hasArg ? `<${commandName}-arg>` : '';
|
|
237
|
+
// choose a representative value option to show
|
|
211
238
|
const valueOpts = options.filter((o) => o.kind === 'value');
|
|
212
239
|
const boolOpts = options.filter((o) => o.kind === 'boolean');
|
|
240
|
+
const exampleParts = [`yarn mono ${commandName}`];
|
|
241
|
+
if (argToken)
|
|
242
|
+
exampleParts.push(argToken);
|
|
243
|
+
// include at most 2 value options and 1 boolean in the example for readability
|
|
213
244
|
for (const o of valueOpts.slice(0, 2)) {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
parts.push(`--${o.key} ${value}`);
|
|
245
|
+
const flag = `--${o.key}`;
|
|
246
|
+
const val = o.default !== undefined ? o.default : (o.allowed?.[0] ?? '<value>');
|
|
247
|
+
exampleParts.push(`${flag} ${val}`);
|
|
218
248
|
}
|
|
219
|
-
if (boolOpts
|
|
220
|
-
|
|
249
|
+
if (boolOpts.length) {
|
|
250
|
+
exampleParts.push(`--${boolOpts[0].key}`);
|
|
221
251
|
}
|
|
222
|
-
return
|
|
252
|
+
return exampleParts.join(' ');
|
|
223
253
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
254
|
+
function formatMonoConfigSection(monoConfig) {
|
|
255
|
+
const lines = [];
|
|
256
|
+
lines.push('## Mono configuration');
|
|
257
|
+
lines.push('');
|
|
258
|
+
if (!monoConfig) {
|
|
259
|
+
lines.push('_No `.mono/config.json` found._');
|
|
260
|
+
return lines.join('\n');
|
|
261
|
+
}
|
|
262
|
+
const c = monoConfig.config;
|
|
263
|
+
lines.push(`Source: \`${toPosix(node_path_1.default.relative(REPO_ROOT, monoConfig.path))}\``);
|
|
264
|
+
lines.push('');
|
|
265
|
+
if (Array.isArray(c.envMap) && c.envMap.length) {
|
|
266
|
+
lines.push('### envMap');
|
|
267
|
+
lines.push('');
|
|
268
|
+
lines.push('- ' + c.envMap.map((x) => `\`${mdEscapeInline(x)}\``).join(', '));
|
|
269
|
+
lines.push('');
|
|
270
|
+
}
|
|
271
|
+
const pkgMaps = c?.workspace?.packageMaps;
|
|
272
|
+
if (pkgMaps && isObject(pkgMaps) && Object.keys(pkgMaps).length) {
|
|
273
|
+
lines.push('### Workspace aliases (packageMaps)');
|
|
274
|
+
lines.push('');
|
|
275
|
+
const entries = Object.entries(pkgMaps).sort(([a], [b]) => a.localeCompare(b));
|
|
276
|
+
for (const [alias, target] of entries) {
|
|
277
|
+
lines.push(`- \`${mdEscapeInline(alias)}\` → \`${mdEscapeInline(String(target))}\``);
|
|
278
|
+
}
|
|
279
|
+
lines.push('');
|
|
280
|
+
}
|
|
281
|
+
const pre = c?.workspace?.preactions;
|
|
282
|
+
if (Array.isArray(pre) && pre.length) {
|
|
283
|
+
lines.push('### Global preactions');
|
|
284
|
+
lines.push('');
|
|
285
|
+
lines.push('```bash');
|
|
286
|
+
for (const p of pre)
|
|
287
|
+
lines.push(String(p));
|
|
288
|
+
lines.push('```');
|
|
289
|
+
lines.push('');
|
|
231
290
|
}
|
|
291
|
+
if (typeof c.prodFlag === 'string' && c.prodFlag.trim()) {
|
|
292
|
+
lines.push('### prodFlag');
|
|
293
|
+
lines.push('');
|
|
294
|
+
lines.push(`Production flag keyword: \`${mdEscapeInline(c.prodFlag.trim())}\``);
|
|
295
|
+
lines.push('');
|
|
296
|
+
}
|
|
297
|
+
return lines.join('\n');
|
|
298
|
+
}
|
|
299
|
+
function formatMonoCommandsSection(commands) {
|
|
300
|
+
const lines = [];
|
|
301
|
+
lines.push('## Mono commands');
|
|
302
|
+
lines.push('');
|
|
303
|
+
lines.push('Generated from `.mono/*.json` (excluding `config.json`). Each filename becomes a command:');
|
|
304
|
+
lines.push('');
|
|
305
|
+
lines.push('```bash');
|
|
306
|
+
lines.push('yarn mono <command> [argument] [--options]');
|
|
307
|
+
lines.push('```');
|
|
308
|
+
lines.push('');
|
|
309
|
+
if (!commands.length) {
|
|
310
|
+
lines.push('_No mono command JSON files found._');
|
|
311
|
+
return lines.join('\n');
|
|
312
|
+
}
|
|
313
|
+
// Index
|
|
314
|
+
lines.push('### Command index');
|
|
315
|
+
lines.push('');
|
|
316
|
+
for (const c of commands) {
|
|
317
|
+
const desc = typeof c.json?.description === 'string' ? c.json.description.trim() : '';
|
|
318
|
+
const suffix = desc ? ` — ${desc}` : '';
|
|
319
|
+
lines.push(`- [\`${mdEscapeInline(c.name)}\`](#mono-command-${mdEscapeInline(c.name).toLowerCase()})${suffix}`);
|
|
320
|
+
}
|
|
321
|
+
lines.push('');
|
|
322
|
+
for (const c of commands) {
|
|
323
|
+
const j = c.json || {};
|
|
324
|
+
const rel = toPosix(node_path_1.default.relative(REPO_ROOT, c.file));
|
|
325
|
+
const anchor = `mono-command-${c.name.toLowerCase()}`;
|
|
326
|
+
const desc = typeof j.description === 'string' ? j.description.trim() : '';
|
|
327
|
+
const arg = j.argument;
|
|
328
|
+
const options = parseOptionsSchema(j.options);
|
|
329
|
+
lines.push('---');
|
|
330
|
+
lines.push(`### Mono command: ${c.name}`);
|
|
331
|
+
lines.push(`<a id="${anchor}"></a>`);
|
|
332
|
+
lines.push('');
|
|
333
|
+
lines.push(`Source: \`${rel}\``);
|
|
334
|
+
lines.push('');
|
|
335
|
+
if (desc) {
|
|
336
|
+
lines.push(`**Description:** ${mdEscapeInline(desc)}`);
|
|
337
|
+
lines.push('');
|
|
338
|
+
}
|
|
339
|
+
// Usage
|
|
340
|
+
lines.push('**Usage**');
|
|
341
|
+
lines.push('');
|
|
342
|
+
lines.push('```bash');
|
|
343
|
+
lines.push(`yarn mono ${c.name}${isObject(arg) ? ` <${c.name}-arg>` : ''} [--options]`);
|
|
344
|
+
lines.push('```');
|
|
345
|
+
lines.push('');
|
|
346
|
+
lines.push('Example:');
|
|
347
|
+
lines.push('');
|
|
348
|
+
lines.push('```bash');
|
|
349
|
+
lines.push(buildUsageExample(c.name, j, options));
|
|
350
|
+
lines.push('```');
|
|
351
|
+
lines.push('');
|
|
352
|
+
// Argument
|
|
353
|
+
if (isObject(arg)) {
|
|
354
|
+
lines.push('**Argument**');
|
|
355
|
+
lines.push('');
|
|
356
|
+
const bits = [];
|
|
357
|
+
if (typeof arg.type === 'string')
|
|
358
|
+
bits.push(`type: \`${mdEscapeInline(arg.type)}\``);
|
|
359
|
+
if (arg.default !== undefined)
|
|
360
|
+
bits.push(`default: \`${mdEscapeInline(String(arg.default))}\``);
|
|
361
|
+
if (typeof arg.description === 'string')
|
|
362
|
+
bits.push(mdEscapeInline(arg.description));
|
|
363
|
+
lines.push(`- ${bits.join(' • ') || '_(no details)_'} `);
|
|
364
|
+
lines.push('');
|
|
365
|
+
}
|
|
366
|
+
// Options
|
|
367
|
+
if (options.length) {
|
|
368
|
+
lines.push('**Options**');
|
|
369
|
+
lines.push('');
|
|
370
|
+
lines.push('| Option | Type | Shortcut | Default | Allowed | Notes |');
|
|
371
|
+
lines.push('|---|---:|:---:|---:|---|---|');
|
|
372
|
+
for (const o of options) {
|
|
373
|
+
const optCol = o.kind === 'boolean' ?
|
|
374
|
+
`\`--${mdEscapeInline(o.key)}\``
|
|
375
|
+
: `\`--${mdEscapeInline(o.key)} <${mdEscapeInline(o.key)}>\``;
|
|
376
|
+
const typeCol = `\`${mdEscapeInline(o.type)}\``;
|
|
377
|
+
const shortCol = o.shortcut ? `\`-${mdEscapeInline(o.shortcut)}\`` : '';
|
|
378
|
+
const defCol = o.default !== undefined ? `\`${mdEscapeInline(o.default)}\`` : '';
|
|
379
|
+
const allowedCol = o.allowed ?
|
|
380
|
+
o.allowed.map((x) => `\`${mdEscapeInline(x)}\``).join(', ')
|
|
381
|
+
: '';
|
|
382
|
+
const notes = [
|
|
383
|
+
o.allowAll ? 'allowAll' : '',
|
|
384
|
+
o.description ? mdEscapeInline(o.description) : '',
|
|
385
|
+
]
|
|
386
|
+
.filter(Boolean)
|
|
387
|
+
.join(' • ');
|
|
388
|
+
lines.push(`| ${optCol} | ${typeCol} | ${shortCol} | ${defCol} | ${allowedCol} | ${notes} |`);
|
|
389
|
+
}
|
|
390
|
+
lines.push('');
|
|
391
|
+
}
|
|
392
|
+
// Environments
|
|
393
|
+
if (j.environments &&
|
|
394
|
+
isObject(j.environments) &&
|
|
395
|
+
Object.keys(j.environments).length) {
|
|
396
|
+
lines.push('**Environment Variables**');
|
|
397
|
+
lines.push('');
|
|
398
|
+
const envs = Object.entries(j.environments).sort(([a], [b]) => a.localeCompare(b));
|
|
399
|
+
for (const [envName, envObj] of envs) {
|
|
400
|
+
lines.push(`- \`${mdEscapeInline(envName)}\``);
|
|
401
|
+
if (isObject(envObj) && Object.keys(envObj).length) {
|
|
402
|
+
const kv = Object.entries(envObj).sort(([a], [b]) => a.localeCompare(b));
|
|
403
|
+
lines.push(indentLines(kv
|
|
404
|
+
.map(([k, v]) => `- \`${mdEscapeInline(k)}\` = \`${mdEscapeInline(String(v))}\``)
|
|
405
|
+
.join('\n'), 2));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
lines.push('');
|
|
409
|
+
}
|
|
410
|
+
// preactions/actions
|
|
411
|
+
if (Array.isArray(j.preactions) && j.preactions.length) {
|
|
412
|
+
lines.push('**Preactions**');
|
|
413
|
+
lines.push('');
|
|
414
|
+
lines.push('```bash');
|
|
415
|
+
for (const p of j.preactions)
|
|
416
|
+
lines.push(String(p));
|
|
417
|
+
lines.push('```');
|
|
418
|
+
lines.push('');
|
|
419
|
+
}
|
|
420
|
+
if (Array.isArray(j.actions) && j.actions.length) {
|
|
421
|
+
lines.push('**Actions**');
|
|
422
|
+
lines.push('');
|
|
423
|
+
lines.push('```bash');
|
|
424
|
+
for (const a of j.actions)
|
|
425
|
+
lines.push(String(a));
|
|
426
|
+
lines.push('```');
|
|
427
|
+
lines.push('');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return lines.join('\n');
|
|
431
|
+
}
|
|
432
|
+
function collectScripts(packages) {
|
|
433
|
+
const scriptToPackages = new Map();
|
|
434
|
+
for (const p of packages) {
|
|
435
|
+
for (const scriptName of Object.keys(p.scripts || {})) {
|
|
436
|
+
if (!scriptToPackages.has(scriptName))
|
|
437
|
+
scriptToPackages.set(scriptName, []);
|
|
438
|
+
scriptToPackages.get(scriptName).push(p.name);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return scriptToPackages;
|
|
442
|
+
}
|
|
443
|
+
// ---------- main ----------
|
|
444
|
+
async function main() {
|
|
445
|
+
if (!(await exists(ROOT_PKG_JSON)))
|
|
446
|
+
throw new Error(`Missing: ${ROOT_PKG_JSON}`);
|
|
232
447
|
await ensureParentDir(OUTPUT_PATH);
|
|
233
448
|
const rootPkg = await readJson(ROOT_PKG_JSON);
|
|
234
449
|
const workspacePatterns = normalizeWorkspacePatterns(rootPkg.workspaces);
|
|
235
450
|
const monoConfig = await readMonoConfig();
|
|
236
451
|
const monoCommands = await readMonoCommands();
|
|
237
452
|
const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns);
|
|
453
|
+
console.log(`[main] Package directories found:`, pkgDirs);
|
|
238
454
|
const packages = [];
|
|
239
455
|
for (const dir of pkgDirs) {
|
|
240
456
|
try {
|
|
241
|
-
const
|
|
457
|
+
const pkgPath = node_path_1.default.join(dir, 'package.json');
|
|
458
|
+
console.log(`[main] Reading package.json:`, pkgPath);
|
|
459
|
+
const pj = await readJson(pkgPath);
|
|
242
460
|
packages.push({
|
|
243
|
-
name:
|
|
244
|
-
toPosix(node_path_1.default.relative(REPO_ROOT, dir))
|
|
461
|
+
name: pj.name ||
|
|
462
|
+
toPosix(node_path_1.default.relative(REPO_ROOT, dir)) ||
|
|
245
463
|
node_path_1.default.basename(dir),
|
|
246
464
|
dir,
|
|
247
|
-
scripts:
|
|
465
|
+
scripts: pj.scripts || {},
|
|
248
466
|
});
|
|
467
|
+
console.log(`[main] Loaded package:`, pj.name || dir);
|
|
249
468
|
}
|
|
250
|
-
catch {
|
|
251
|
-
|
|
469
|
+
catch (err) {
|
|
470
|
+
console.error(`[main] Failed to load package.json for:`, dir, err);
|
|
471
|
+
// skip
|
|
252
472
|
}
|
|
253
473
|
}
|
|
254
474
|
const parts = [];
|
|
255
475
|
parts.push(`# Mono Command-Line Reference
|
|
256
476
|
|
|
257
|
-
> Generated by \`scripts/generate-readme.
|
|
477
|
+
> Generated by \`scripts/generate-readme.mjs\`.
|
|
478
|
+
> Update \`.mono/config.json\`, \`.mono/*.json\`, and workspace package scripts to change this output.
|
|
258
479
|
|
|
259
480
|
`);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
481
|
+
parts.push(formatMonoConfigSection(monoConfig));
|
|
482
|
+
parts.push('');
|
|
483
|
+
parts.push(formatMonoCommandsSection(monoCommands));
|
|
484
|
+
parts.push('');
|
|
485
|
+
const val = await (0, generate_docs_js_1.generateDocsIndex)({
|
|
263
486
|
docsDir: node_path_1.default.join(REPO_ROOT, 'docs'),
|
|
264
487
|
excludeFile: 'command-line.md',
|
|
265
488
|
});
|
|
266
|
-
parts.push(
|
|
489
|
+
val.split('\n').forEach((line) => parts.push(line));
|
|
267
490
|
await ensureParentDir(OUTPUT_README);
|
|
268
491
|
await node_fs_1.promises.writeFile(OUTPUT_README, parts.join('\n'), 'utf8');
|
|
269
|
-
console.log(`Generated: ${OUTPUT_README}`);
|
|
270
|
-
console.log(
|
|
271
|
-
console.log(
|
|
272
|
-
console.log(
|
|
492
|
+
console.log(`[main] Generated: ${OUTPUT_README}`);
|
|
493
|
+
console.log(`[main] mono config: ${monoConfig ? 'yes' : 'no'}`);
|
|
494
|
+
console.log(`[main] mono commands: ${monoCommands.length}`);
|
|
495
|
+
console.log(`[main] workspace packages: ${packages.length}`);
|
|
273
496
|
}
|
|
274
497
|
main().catch((err) => {
|
|
275
|
-
console.error(err
|
|
276
|
-
process.
|
|
498
|
+
console.error(err?.stack || String(err));
|
|
499
|
+
process.exitCode = 1;
|
|
277
500
|
});
|