@mono-labs/cli 0.0.246 → 0.0.248

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.
Files changed (110) hide show
  1. package/dist/{types/index.d.ts → index.d.ts} +1 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/{types/lib → lib}/app.d.ts +1 -0
  4. package/dist/lib/app.d.ts.map +1 -0
  5. package/dist/{types/lib → lib}/commands/build-process/boot.d.ts +1 -0
  6. package/dist/lib/commands/build-process/boot.d.ts.map +1 -0
  7. package/dist/{types/lib → lib}/commands/build-process/cliFactory.d.ts +1 -0
  8. package/dist/lib/commands/build-process/cliFactory.d.ts.map +1 -0
  9. package/dist/{types/lib → lib}/commands/build-process/dataLayer.d.ts +1 -0
  10. package/dist/lib/commands/build-process/dataLayer.d.ts.map +1 -0
  11. package/dist/lib/commands/build-process/index.d.ts +2 -0
  12. package/dist/lib/commands/build-process/index.d.ts.map +1 -0
  13. package/dist/{types/lib → lib}/commands/build-process/readEnv.d.ts +1 -0
  14. package/dist/lib/commands/build-process/readEnv.d.ts.map +1 -0
  15. package/dist/{types/lib → lib}/commands/build-process/runMonoCommand.d.ts +1 -0
  16. package/dist/lib/commands/build-process/runMonoCommand.d.ts.map +1 -0
  17. package/dist/{types/lib → lib}/commands/build-process/runners/processManager.d.ts +1 -0
  18. package/dist/lib/commands/build-process/runners/processManager.d.ts.map +1 -0
  19. package/dist/{types/lib → lib}/commands/build-process/runners/runBackground.d.ts +1 -0
  20. package/dist/lib/commands/build-process/runners/runBackground.d.ts.map +1 -0
  21. package/dist/{types/lib → lib}/commands/build-process/runners/runForeground.d.ts +1 -0
  22. package/dist/lib/commands/build-process/runners/runForeground.d.ts.map +1 -0
  23. package/dist/lib/commands/build-process/runners/runForeground.js +1 -1
  24. package/dist/{types/lib → lib}/commands/build-process/test.d.ts +1 -0
  25. package/dist/lib/commands/build-process/test.d.ts.map +1 -0
  26. package/dist/lib/commands/build-process/testflag.d.ts +2 -0
  27. package/dist/lib/commands/build-process/testflag.d.ts.map +1 -0
  28. package/dist/{types/lib → lib}/commands/build-process/validators.d.ts +1 -0
  29. package/dist/lib/commands/build-process/validators.d.ts.map +1 -0
  30. package/dist/{types/lib → lib}/commands/loadFromRoot.d.ts +1 -0
  31. package/dist/lib/commands/loadFromRoot.d.ts.map +1 -0
  32. package/dist/lib/commands/prune/index.d.ts +2 -0
  33. package/dist/lib/commands/prune/index.d.ts.map +1 -0
  34. package/dist/{types/lib → lib}/commands/prune/prune.d.ts +1 -0
  35. package/dist/lib/commands/prune/prune.d.ts.map +1 -0
  36. package/dist/{types/lib → lib}/config.d.ts +1 -0
  37. package/dist/lib/config.d.ts.map +1 -0
  38. package/dist/{types/lib → lib}/filterUnwantedEnvVars.d.ts +1 -0
  39. package/dist/lib/filterUnwantedEnvVars.d.ts.map +1 -0
  40. package/dist/{types/lib → lib}/generateNewEnvList.d.ts +1 -0
  41. package/dist/lib/generateNewEnvList.d.ts.map +1 -0
  42. package/dist/{types/lib → lib}/index.d.ts +1 -0
  43. package/dist/lib/index.d.ts.map +1 -0
  44. package/dist/lib/index.js +2 -2
  45. package/dist/src/cdk.d.ts +2 -0
  46. package/dist/src/cdk.d.ts.map +1 -0
  47. package/dist/src/{cdk/cdk.js → cdk.js} +4 -3
  48. package/dist/src/expo.d.ts +2 -0
  49. package/dist/src/expo.d.ts.map +1 -0
  50. package/dist/src/expo.js +6 -111
  51. package/dist/{types/src → src}/index.d.ts +2 -1
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/index.js +7 -7
  54. package/dist/src/project.d.ts +3 -0
  55. package/dist/src/project.d.ts.map +1 -0
  56. package/dist/src/project.js +14 -0
  57. package/dist/{types/src → src}/stack.d.ts +1 -0
  58. package/dist/src/stack.d.ts.map +1 -0
  59. package/dist/src/stack.js +4 -4
  60. package/dist/src/tools.d.ts +2 -0
  61. package/dist/src/tools.d.ts.map +1 -0
  62. package/dist/src/tools.js +5 -36
  63. package/dist/tsconfig.tsbuildinfo +1 -0
  64. package/lib/commands/build-process/runners/runForeground.ts +1 -1
  65. package/lib/index.ts +1 -1
  66. package/package.json +41 -26
  67. package/src/cdk.ts +2 -0
  68. package/src/expo.ts +2 -116
  69. package/src/index.ts +2 -2
  70. package/src/project.ts +19 -0
  71. package/src/stack.ts +3 -3
  72. package/src/tools.ts +2 -39
  73. package/README.md +0 -123
  74. package/dist/src/cdk/index.js +0 -17
  75. package/dist/src/expo-files/filterUnwantedEnvVars.js +0 -147
  76. package/dist/src/loadFromRoot.js +0 -115
  77. package/dist/src/merge-env.js +0 -25
  78. package/dist/src/project/build-mono-readme.js +0 -456
  79. package/dist/src/project/build-readme.js +0 -4
  80. package/dist/src/project/generate-docs.js +0 -73
  81. package/dist/src/project/generate-readme.js +0 -309
  82. package/dist/src/project/index.js +0 -120
  83. package/dist/src/project/merge-env.js +0 -31
  84. package/dist/types/lib/commands/build-process/index.d.ts +0 -1
  85. package/dist/types/lib/commands/build-process/testflag.d.ts +0 -1
  86. package/dist/types/lib/commands/prune/index.d.ts +0 -1
  87. package/dist/types/src/cdk/cdk.d.ts +0 -1
  88. package/dist/types/src/cdk/index.d.ts +0 -1
  89. package/dist/types/src/expo-files/filterUnwantedEnvVars.d.ts +0 -3
  90. package/dist/types/src/expo.d.ts +0 -4
  91. package/dist/types/src/loadFromRoot.d.ts +0 -32
  92. package/dist/types/src/merge-env.d.ts +0 -1
  93. package/dist/types/src/project/build-mono-readme.d.ts +0 -1
  94. package/dist/types/src/project/build-readme.d.ts +0 -2
  95. package/dist/types/src/project/generate-docs.d.ts +0 -11
  96. package/dist/types/src/project/generate-readme.d.ts +0 -1
  97. package/dist/types/src/project/index.d.ts +0 -40
  98. package/dist/types/src/project/merge-env.d.ts +0 -1
  99. package/dist/types/src/tools.d.ts +0 -3
  100. package/src/cdk/cdk.ts +0 -1
  101. package/src/cdk/index.ts +0 -1
  102. package/src/expo-files/filterUnwantedEnvVars.ts +0 -155
  103. package/src/loadFromRoot.ts +0 -145
  104. package/src/merge-env.ts +0 -24
  105. package/src/project/build-mono-readme.ts +0 -545
  106. package/src/project/build-readme.ts +0 -2
  107. package/src/project/generate-docs.ts +0 -83
  108. package/src/project/generate-readme.ts +0 -351
  109. package/src/project/index.ts +0 -187
  110. package/src/project/merge-env.ts +0 -32
@@ -1,545 +0,0 @@
1
- // scripts/generate-readme.mjs
2
- // Node >= 18 recommended
3
- import { promises as fs } from 'node:fs'
4
- import { Dirent } from 'node:fs'
5
- import path from 'node:path'
6
- import { generateDocsIndex } from './generate-docs'
7
-
8
- const REPO_ROOT = path.resolve(process.cwd())
9
- const MONO_DIR = path.join(REPO_ROOT, '.mono')
10
- const ROOT_PKG_JSON = path.join(REPO_ROOT, 'package.json')
11
- const OUTPUT_PATH = path.join(REPO_ROOT, 'docs')
12
- const OUTPUT_README = path.join(OUTPUT_PATH, 'command-line.md')
13
-
14
- async function ensureParentDir(filePath: string): Promise<void> {
15
- const dir = path.dirname(filePath)
16
- await fs.mkdir(dir, { recursive: true })
17
- }
18
-
19
- // ---------- utils ----------
20
- async function exists(p: string): Promise<boolean> {
21
- try {
22
- await fs.access(p)
23
- // Log existence check
24
-
25
- return true
26
- } catch {
27
- return false
28
- }
29
- }
30
- function isObject(v: unknown): v is Record<string, unknown> {
31
- return v !== null && typeof v === 'object' && !Array.isArray(v)
32
- }
33
- function toPosix(p: string): string {
34
- return p.split(path.sep).join('/')
35
- }
36
- async function readJson<T = any>(filePath: string): Promise<T> {
37
- const raw = await fs.readFile(filePath, 'utf8')
38
- try {
39
- const parsed = JSON.parse(raw)
40
-
41
- return parsed
42
- } catch (err) {
43
- throw err
44
- }
45
- }
46
- async function listDir(dir: string): Promise<Dirent[]> {
47
- const entries = await fs.readdir(dir, { withFileTypes: true })
48
-
49
- return entries
50
- }
51
- function normalizeWorkspacePatterns(workspacesField: unknown): string[] {
52
- if (Array.isArray(workspacesField)) return workspacesField as string[]
53
- if (isObject(workspacesField) && Array.isArray((workspacesField as any).packages))
54
- return (workspacesField as any).packages
55
- return []
56
- }
57
- function mdEscapeInline(s: string): string {
58
- return String(s ?? '').replaceAll('`', '\`')
59
- }
60
- function indentLines(s: string, spaces = 2): string {
61
- const pad = ' '.repeat(spaces)
62
- return String(s ?? '')
63
- .split('\n')
64
- .map((l) => pad + l)
65
- .join('\n')
66
- }
67
-
68
- // ---------- workspace glob matching (supports *, **, and plain segments) ----------
69
- function matchSegment(patternSeg: string, name: string): boolean {
70
- if (patternSeg === '*') return true
71
- if (!patternSeg.includes('*')) return patternSeg === name
72
- const escaped = patternSeg.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
73
- const regex = new RegExp('^' + escaped.replaceAll('*', '.*') + '$')
74
- return regex.test(name)
75
- }
76
-
77
- async function expandWorkspacePattern(root: string, pattern: string): Promise<string[]> {
78
- const segs = toPosix(pattern).split('/').filter(Boolean)
79
-
80
- async function expandFrom(dir: string, segIndex: number): Promise<string[]> {
81
- if (segIndex >= segs.length) return [dir]
82
- const seg = segs[segIndex]
83
-
84
- if (seg === '**') {
85
- const results: string[] = []
86
- results.push(...(await expandFrom(dir, segIndex + 1)))
87
- const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
88
-
89
- for (const e of entries) {
90
- if (!e.isDirectory()) continue
91
-
92
- results.push(...(await expandFrom(path.join(dir, e.name), segIndex)))
93
- }
94
- return results
95
- }
96
-
97
- const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])
98
-
99
- const results: string[] = []
100
- for (const e of entries) {
101
- if (!e.isDirectory()) continue
102
- if (!matchSegment(seg, e.name)) continue
103
-
104
- results.push(...(await expandFrom(path.join(dir, e.name), segIndex + 1)))
105
- }
106
- return results
107
- }
108
-
109
- const dirs = await expandFrom(root, 0)
110
-
111
- const pkgDirs: string[] = []
112
- for (const d of dirs) {
113
- const pkgPath = path.join(d, 'package.json')
114
- if (await exists(pkgPath)) {
115
- pkgDirs.push(d)
116
- }
117
- }
118
-
119
- return [...new Set(pkgDirs)]
120
- }
121
-
122
- async function findWorkspacePackageDirs(
123
- repoRoot: string,
124
- workspacePatterns: string[]
125
- ): Promise<string[]> {
126
- const dirs: string[] = []
127
- for (const pat of workspacePatterns) {
128
- const expanded = await expandWorkspacePattern(repoRoot, pat)
129
- dirs.push(...expanded)
130
- dirs.push(...expanded)
131
- }
132
- const uniqueDirs = [...new Set(dirs)]
133
- return uniqueDirs
134
- }
135
-
136
- // ---------- .mono parsing ----------
137
- async function readMonoConfig(): Promise<MonoConfig | null> {
138
- const configPath = path.join(MONO_DIR, 'config.json')
139
- console.log(`[readMonoConfig] Looking for mono config at:`, configPath)
140
- if (!(await exists(configPath))) {
141
- console.log(`[readMonoConfig] No mono config found.`)
142
- return null
143
- }
144
- try {
145
- const config = await readJson<any>(configPath)
146
- return { path: configPath, config }
147
- } catch (err) {
148
- return null
149
- }
150
- }
151
-
152
- function commandNameFromFile(filePath: string): string {
153
- return path.basename(filePath).replace(/\.json$/i, '')
154
- }
155
-
156
- async function readMonoCommands(): Promise<MonoCommand[]> {
157
- if (!(await exists(MONO_DIR))) {
158
- return []
159
- }
160
- const entries = await listDir(MONO_DIR)
161
-
162
- const jsonFiles = entries
163
- .filter((e) => e.isFile() && e.name.toLowerCase().endsWith('.json'))
164
- .map((e) => path.join(MONO_DIR, e.name))
165
- .filter((p) => path.basename(p).toLowerCase() !== 'config.json')
166
-
167
- const commands: MonoCommand[] = []
168
- for (const file of jsonFiles) {
169
- try {
170
- const j = await readJson<any>(file)
171
- commands.push({
172
- name: commandNameFromFile(file),
173
- file,
174
- json: j,
175
- })
176
- } catch (err) {
177
- console.error(`[readMonoCommands] Failed to load command file:`, file, err)
178
- // skip invalid json
179
- }
180
- }
181
-
182
- commands.sort((a, b) => a.name.localeCompare(b.name))
183
-
184
- return commands
185
- }
186
-
187
- // ---------- mono docs formatting ----------
188
- type OptionSchema = {
189
- key: string
190
- kind: 'boolean' | 'value'
191
- type: string
192
- description: string
193
- shortcut: string
194
- default: any
195
- allowed: string[] | null
196
- allowAll: boolean
197
- }
198
-
199
- type MonoConfig = {
200
- path: string
201
- config: any
202
- }
203
-
204
- function parseOptionsSchema(optionsObj: unknown): OptionSchema[] {
205
- // New structure supports:
206
- // - optionKey: { type: "string", default, options: [], allowAll, shortcut, description }
207
- // - boolean toggle: { shortcut, description } (no type)
208
- if (!isObject(optionsObj)) return []
209
-
210
- const entries: OptionSchema[] = Object.entries(optionsObj).map(([key, raw]) => {
211
- const o = isObject(raw) ? raw : {}
212
- const hasType = typeof o.type === 'string' && o.type.trim().length > 0
213
- const isBoolToggle = !hasType // in your examples, booleans omit `type`
214
- return {
215
- key,
216
- kind: isBoolToggle ? 'boolean' : 'value',
217
- type: hasType ? String(o.type) : 'boolean',
218
- description: typeof o.description === 'string' ? o.description : '',
219
- shortcut: typeof o.shortcut === 'string' ? o.shortcut : '',
220
- default: o.default,
221
- allowed: Array.isArray(o.options) ? o.options : null,
222
- allowAll: o.allowAll === true,
223
- }
224
- })
225
-
226
- entries.sort((a, b) => a.key.localeCompare(b.key))
227
- return entries
228
- }
229
-
230
- function buildUsageExample(commandName: string, cmdJson: any, options: OptionSchema[]): string {
231
- const arg = cmdJson?.argument
232
- const hasArg = isObject(arg)
233
- const argToken = hasArg ? `<${commandName}-arg>` : ''
234
-
235
- // choose a representative value option to show
236
- const valueOpts = options.filter((o) => o.kind === 'value')
237
- const boolOpts = options.filter((o) => o.kind === 'boolean')
238
-
239
- const exampleParts = [`yarn mono ${commandName}`]
240
- if (argToken) exampleParts.push(argToken)
241
-
242
- // include at most 2 value options and 1 boolean in the example for readability
243
- for (const o of valueOpts.slice(0, 2)) {
244
- const flag = `--${o.key}`
245
- const val = o.default !== undefined ? o.default : (o.allowed?.[0] ?? '<value>')
246
- exampleParts.push(`${flag} ${val}`)
247
- }
248
- if (boolOpts.length) {
249
- exampleParts.push(`--${boolOpts[0].key}`)
250
- }
251
-
252
- return exampleParts.join(' ')
253
- }
254
-
255
- function formatMonoConfigSection(monoConfig: MonoConfig | null): string {
256
- const lines: string[] = []
257
- lines.push('## Mono configuration')
258
- lines.push('')
259
-
260
- if (!monoConfig) {
261
- lines.push('_No `.mono/config.json` found._')
262
- return lines.join('\n')
263
- }
264
-
265
- const c = monoConfig.config
266
- lines.push(`Source: \`${toPosix(path.relative(REPO_ROOT, monoConfig.path))}\``)
267
- lines.push('')
268
-
269
- if (Array.isArray(c.envMap) && c.envMap.length) {
270
- lines.push('### envMap')
271
- lines.push('')
272
- lines.push('- ' + c.envMap.map((x: string) => `\`${mdEscapeInline(x)}\``).join(', '))
273
- lines.push('')
274
- }
275
-
276
- const pkgMaps = c?.workspace?.packageMaps
277
- if (pkgMaps && isObject(pkgMaps) && Object.keys(pkgMaps).length) {
278
- lines.push('### Workspace aliases (packageMaps)')
279
- lines.push('')
280
- const entries = Object.entries(pkgMaps).sort(([a], [b]) => a.localeCompare(b))
281
- for (const [alias, target] of entries) {
282
- lines.push(`- \`${mdEscapeInline(alias)}\` → \`${mdEscapeInline(String(target))}\``)
283
- }
284
- lines.push('')
285
- }
286
-
287
- const pre = c?.workspace?.preactions
288
- if (Array.isArray(pre) && pre.length) {
289
- lines.push('### Global preactions')
290
- lines.push('')
291
- lines.push('```bash')
292
- for (const p of pre) lines.push(String(p))
293
- lines.push('```')
294
- lines.push('')
295
- }
296
-
297
- if (typeof c.prodFlag === 'string' && c.prodFlag.trim()) {
298
- lines.push('### prodFlag')
299
- lines.push('')
300
- lines.push(`Production flag keyword: \`${mdEscapeInline(c.prodFlag.trim())}\``)
301
- lines.push('')
302
- }
303
-
304
- return lines.join('\n')
305
- }
306
-
307
- type MonoCommand = {
308
- name: string
309
- file: string
310
- json: any
311
- }
312
-
313
- function formatMonoCommandsSection(commands: MonoCommand[]): string {
314
- const lines: string[] = []
315
- lines.push('## Mono commands')
316
- lines.push('')
317
- lines.push(
318
- 'Generated from `.mono/*.json` (excluding `config.json`). Each filename becomes a command:'
319
- )
320
- lines.push('')
321
- lines.push('```bash')
322
- lines.push('yarn mono <command> [argument] [--options]')
323
- lines.push('```')
324
- lines.push('')
325
-
326
- if (!commands.length) {
327
- lines.push('_No mono command JSON files found._')
328
- return lines.join('\n')
329
- }
330
-
331
- // Index
332
- lines.push('### Command index')
333
- lines.push('')
334
- for (const c of commands) {
335
- const desc = typeof c.json?.description === 'string' ? c.json.description.trim() : ''
336
- const suffix = desc ? ` — ${desc}` : ''
337
- lines.push(
338
- `- [\`${mdEscapeInline(c.name)}\`](#mono-command-${mdEscapeInline(c.name).toLowerCase()})${suffix}`
339
- )
340
- }
341
- lines.push('')
342
-
343
- for (const c of commands) {
344
- const j = c.json || {}
345
- const rel = toPosix(path.relative(REPO_ROOT, c.file))
346
- const anchor = `mono-command-${c.name.toLowerCase()}`
347
-
348
- const desc = typeof j.description === 'string' ? j.description.trim() : ''
349
- const arg = j.argument
350
- const options = parseOptionsSchema(j.options)
351
-
352
- lines.push('---')
353
- lines.push(`### Mono command: ${c.name}`)
354
- lines.push(`<a id="${anchor}"></a>`)
355
- lines.push('')
356
- lines.push(`Source: \`${rel}\``)
357
- lines.push('')
358
-
359
- if (desc) {
360
- lines.push(`**Description:** ${mdEscapeInline(desc)}`)
361
- lines.push('')
362
- }
363
-
364
- // Usage
365
- lines.push('**Usage**')
366
- lines.push('')
367
- lines.push('```bash')
368
- lines.push(`yarn mono ${c.name}${isObject(arg) ? ` <${c.name}-arg>` : ''} [--options]`)
369
- lines.push('```')
370
- lines.push('')
371
- lines.push('Example:')
372
- lines.push('')
373
- lines.push('```bash')
374
- lines.push(buildUsageExample(c.name, j, options))
375
- lines.push('```')
376
- lines.push('')
377
-
378
- // Argument
379
- if (isObject(arg)) {
380
- lines.push('**Argument**')
381
- lines.push('')
382
- const bits: string[] = []
383
- if (typeof arg.type === 'string') bits.push(`type: \`${mdEscapeInline(arg.type)}\``)
384
- if (arg.default !== undefined)
385
- bits.push(`default: \`${mdEscapeInline(String(arg.default))}\``)
386
- if (typeof arg.description === 'string') bits.push(mdEscapeInline(arg.description))
387
- lines.push(`- ${bits.join(' • ') || '_(no details)_'} `)
388
- lines.push('')
389
- }
390
-
391
- // Options
392
- if (options.length) {
393
- lines.push('**Options**')
394
- lines.push('')
395
- lines.push('| Option | Type | Shortcut | Default | Allowed | Notes |')
396
- lines.push('|---|---:|:---:|---:|---|---|')
397
- for (const o of options) {
398
- const optCol =
399
- o.kind === 'boolean'
400
- ? `\`--${mdEscapeInline(o.key)}\``
401
- : `\`--${mdEscapeInline(o.key)} <${mdEscapeInline(o.key)}>\``
402
- const typeCol = `\`${mdEscapeInline(o.type)}\``
403
- const shortCol = o.shortcut ? `\`-${mdEscapeInline(o.shortcut)}\`` : ''
404
- const defCol = o.default !== undefined ? `\`${mdEscapeInline(o.default)}\`` : ''
405
- const allowedCol = o.allowed
406
- ? o.allowed.map((x) => `\`${mdEscapeInline(x)}\``).join(', ')
407
- : ''
408
- const notes = [
409
- o.allowAll ? 'allowAll' : '',
410
- o.description ? mdEscapeInline(o.description) : '',
411
- ]
412
- .filter(Boolean)
413
- .join(' • ')
414
- lines.push(
415
- `| ${optCol} | ${typeCol} | ${shortCol} | ${defCol} | ${allowedCol} | ${notes} |`
416
- )
417
- }
418
- lines.push('')
419
- }
420
-
421
- // Environments
422
- if (j.environments && isObject(j.environments) && Object.keys(j.environments).length) {
423
- lines.push('**Environment Variables**')
424
- lines.push('')
425
- const envs = Object.entries(j.environments).sort(([a], [b]) => a.localeCompare(b))
426
- for (const [envName, envObj] of envs) {
427
- lines.push(`- \`${mdEscapeInline(envName)}\``)
428
- if (isObject(envObj) && Object.keys(envObj).length) {
429
- const kv = Object.entries(envObj).sort(([a], [b]) => a.localeCompare(b))
430
- lines.push(
431
- indentLines(
432
- kv
433
- .map(([k, v]) => `- \`${mdEscapeInline(k)}\` = \`${mdEscapeInline(String(v))}\``)
434
- .join('\n'),
435
- 2
436
- )
437
- )
438
- }
439
- }
440
- lines.push('')
441
- }
442
-
443
- // preactions/actions
444
- if (Array.isArray(j.preactions) && j.preactions.length) {
445
- lines.push('**Preactions**')
446
- lines.push('')
447
- lines.push('```bash')
448
- for (const p of j.preactions) lines.push(String(p))
449
- lines.push('```')
450
- lines.push('')
451
- }
452
-
453
- if (Array.isArray(j.actions) && j.actions.length) {
454
- lines.push('**Actions**')
455
- lines.push('')
456
- lines.push('```bash')
457
- for (const a of j.actions) lines.push(String(a))
458
- lines.push('```')
459
- lines.push('')
460
- }
461
- }
462
-
463
- return lines.join('\n')
464
- }
465
-
466
- // ---------- workspace scripts summary ----------
467
-
468
- // Define PackageInfo type
469
- type PackageInfo = {
470
- name: string
471
- dir: string
472
- scripts: Record<string, string>
473
- }
474
-
475
- function collectScripts(packages: PackageInfo[]): Map<string, string[]> {
476
- const scriptToPackages = new Map<string, string[]>()
477
- for (const p of packages) {
478
- for (const scriptName of Object.keys(p.scripts || {})) {
479
- if (!scriptToPackages.has(scriptName)) scriptToPackages.set(scriptName, [])
480
- scriptToPackages.get(scriptName)!.push(p.name)
481
- }
482
- }
483
- return scriptToPackages
484
- }
485
-
486
- // ---------- main ----------
487
- async function main(): Promise<void> {
488
- if (!(await exists(ROOT_PKG_JSON))) throw new Error(`Missing: ${ROOT_PKG_JSON}`)
489
- await ensureParentDir(OUTPUT_PATH)
490
-
491
- const rootPkg = await readJson<any>(ROOT_PKG_JSON)
492
- const workspacePatterns = normalizeWorkspacePatterns(rootPkg.workspaces)
493
-
494
- const monoConfig = await readMonoConfig()
495
- const monoCommands = await readMonoCommands()
496
-
497
- const pkgDirs = await findWorkspacePackageDirs(REPO_ROOT, workspacePatterns)
498
- const packages: PackageInfo[] = []
499
- for (const dir of pkgDirs) {
500
- try {
501
- const pkgPath = path.join(dir, 'package.json')
502
- const pj = await readJson<any>(pkgPath)
503
- packages.push({
504
- name: pj.name || toPosix(path.relative(REPO_ROOT, dir)) || path.basename(dir),
505
- dir,
506
- scripts: pj.scripts || {},
507
- })
508
- } catch (err) {
509
- console.error(`[main] Failed to load package.json for:`, dir, err)
510
- // skip
511
- }
512
- }
513
-
514
- const parts: string[] = []
515
- parts.push(`# ⚙️ Command Line Reference
516
-
517
- > Generated by \`scripts/generate-readme.mjs\`.
518
- > Update \`.mono/config.json\`, \`.mono/*.json\`, and workspace package scripts to change this output.
519
-
520
- `)
521
- parts.push(formatMonoConfigSection(monoConfig))
522
- parts.push('')
523
- parts.push(formatMonoCommandsSection(monoCommands))
524
- parts.push('')
525
-
526
- const val = await generateDocsIndex({
527
- docsDir: path.join(REPO_ROOT, 'docs'),
528
- excludeFile: 'command-line.md',
529
- })
530
-
531
- val.split('\n').forEach((line) => parts.push(line))
532
-
533
- await ensureParentDir(OUTPUT_README)
534
- await fs.writeFile(OUTPUT_README, parts.join('\n'), 'utf8')
535
-
536
- console.log(`[main] Generated: ${OUTPUT_README}`)
537
- console.log(`[main] mono config: ${monoConfig ? 'yes' : 'no'}`)
538
- console.log(`[main] mono commands: ${monoCommands.length}`)
539
- console.log(`[main] workspace packages: ${packages.length}`)
540
- }
541
-
542
- main().catch((err) => {
543
- console.error(err?.stack || String(err))
544
- process.exitCode = 1
545
- })
@@ -1,2 +0,0 @@
1
- import './build-mono-readme';
2
- import './generate-readme';
@@ -1,83 +0,0 @@
1
- // scripts/generate-repo-help.mjs
2
- // Generates a developer-friendly workspace command reference.
3
- //
4
- // Output: docs/workspaces.md
5
- //
6
- // Run (from repo root):
7
- // node ./scripts/generate-repo-help.mjs
8
- //
9
- // Philosophy:
10
- // - Optimize for onboarding and day-to-day use
11
- // - Keep raw yarn workspace commands for reference
12
- // - Emphasize `yarn mono` as the primary interface
13
-
14
- import { promises as fs } from 'node:fs';
15
- import path from 'node:path';
16
-
17
- // Type definitions
18
- export interface GenerateDocsIndexOptions {
19
- docsDir: string;
20
- excludeFile?: string;
21
- }
22
-
23
- function createSpacer() {
24
- return '\n\n';
25
- }
26
- /**
27
- * Generate a docs index from markdown files.
28
- *
29
- * @param options - Options for docs index generation
30
- * @returns Markdown-formatted index
31
- */
32
- export async function generateDocsIndex({
33
- docsDir,
34
- excludeFile,
35
- }: GenerateDocsIndexOptions): Promise<string> {
36
- // Always resolve docsDir relative to the working directory
37
- const dirPath = path.resolve(process.cwd(), docsDir);
38
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
39
-
40
- const links: string[] = [];
41
- for (const entry of entries) {
42
- if (!entry.isFile()) continue;
43
- if (!entry.name.endsWith('.md')) continue;
44
-
45
- // Always ignore docs/readme.md (case-insensitive)
46
- if (entry.name.toLowerCase() === 'readme.md') continue;
47
-
48
- // Optionally ignore a caller-specified file
49
- if (excludeFile && entry.name === excludeFile) continue;
50
-
51
- const filePath = path.join(dirPath, entry.name);
52
- const contents = await fs.readFile(filePath, 'utf8');
53
-
54
- // Find first markdown H1
55
- const match = contents.match(/^#\s+(.+)$/m);
56
- if (!match) continue;
57
-
58
- const rawTitle = match[1].trim();
59
- const relativeLink = `./${entry.name}`;
60
-
61
- /**
62
- * Detect leading non-alphanumeric characters (emoji / symbols).
63
- * This matches one or more Unicode characters that are NOT letters or numbers.
64
- */
65
- const leadingSymbolMatch = rawTitle.match(/^([^\p{L}\p{N}]+)\s*(.+)$/u);
66
-
67
- if (leadingSymbolMatch) {
68
- const [, symbol, title] = leadingSymbolMatch;
69
- links.push(`- ${symbol.trim()} [${title.trim()}](${relativeLink})`);
70
- } else {
71
- links.push(`- [${rawTitle.trim()}](${relativeLink})`);
72
- }
73
- }
74
-
75
- // Sort alphabetically by rendered text (stable output)
76
- links.sort((a, b) => a.localeCompare(b));
77
-
78
- // Append Back to Readme
79
- links.push('');
80
- links.push('🏠 ← [Back to README](../README.md)');
81
-
82
- return ['', '---', '', ...links].join('\n');
83
- }