genlayer 0.29.0 → 0.30.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/.github/workflows/cli-docs.yml +121 -0
- package/.github/workflows/publish.yml +2 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.js +3 -2
- package/package.json +3 -2
- package/scripts/generate-cli-docs.mjs +246 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
name: Generate CLI Docs and PR to genlayer-docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
generate-and-sync:
|
|
10
|
+
# Skip for pre-releases (tags containing '-') unless manually dispatched
|
|
11
|
+
if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-')
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout CLI repo
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Setup Node.js
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: '20'
|
|
23
|
+
cache: 'npm'
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm ci
|
|
27
|
+
|
|
28
|
+
- name: Build
|
|
29
|
+
run: npm run build
|
|
30
|
+
|
|
31
|
+
- name: Determine version for docs
|
|
32
|
+
id: version
|
|
33
|
+
run: |
|
|
34
|
+
if [ "${{ github.event_name }}" = "release" ]; then
|
|
35
|
+
echo "value=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
|
36
|
+
else
|
|
37
|
+
# Prefer package.json version when not a release event
|
|
38
|
+
echo "value=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
- name: Generate CLI docs (MDX)
|
|
42
|
+
env:
|
|
43
|
+
DOCS_CLEAN: 'true'
|
|
44
|
+
DOCS_VERSION: ${{ steps.version.outputs.value }}
|
|
45
|
+
run: node scripts/generate-cli-docs.mjs | cat
|
|
46
|
+
|
|
47
|
+
- name: Set up Git (for committing to CLI repo)
|
|
48
|
+
run: |
|
|
49
|
+
git config user.name "github-actions[bot]"
|
|
50
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
51
|
+
|
|
52
|
+
- name: Commit and push docs back to CLI repo (non-beta releases)
|
|
53
|
+
if: github.event_name == 'release' && !contains(github.event.release.tag_name, '-')
|
|
54
|
+
run: |
|
|
55
|
+
set -euo pipefail
|
|
56
|
+
if [ -n "$(git status --porcelain docs/api-references || true)" ]; then
|
|
57
|
+
git add docs/api-references
|
|
58
|
+
VERSION=${{ steps.version.outputs.value }}
|
|
59
|
+
git commit -m "docs(cli): update API reference for ${VERSION}"
|
|
60
|
+
git push
|
|
61
|
+
else
|
|
62
|
+
echo "No docs changes to commit"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
- name: Checkout docs repo
|
|
66
|
+
uses: actions/checkout@v4
|
|
67
|
+
with:
|
|
68
|
+
repository: genlayerlabs/genlayer-docs
|
|
69
|
+
token: ${{ secrets.DOCS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
|
|
70
|
+
path: docs-repo
|
|
71
|
+
fetch-depth: 0
|
|
72
|
+
|
|
73
|
+
- name: Prepare branch
|
|
74
|
+
working-directory: docs-repo
|
|
75
|
+
run: |
|
|
76
|
+
set -euo pipefail
|
|
77
|
+
git config user.name "github-actions[bot]"
|
|
78
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
79
|
+
BRANCH="docs/cli/${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }}"
|
|
80
|
+
git switch -c "$BRANCH" || git switch "$BRANCH"
|
|
81
|
+
echo "BRANCH=$BRANCH" >> $GITHUB_ENV
|
|
82
|
+
|
|
83
|
+
- name: Sync CLI docs into docs repo
|
|
84
|
+
run: |
|
|
85
|
+
set -euo pipefail
|
|
86
|
+
mkdir -p docs-repo/pages/api-references/genlayer-cli
|
|
87
|
+
rsync -a --delete "${{ github.workspace }}/docs/api-references/" docs-repo/pages/api-references/genlayer-cli/
|
|
88
|
+
echo "Synced files:" && ls -la docs-repo/pages/api-references/genlayer-cli | cat
|
|
89
|
+
|
|
90
|
+
- name: Commit changes
|
|
91
|
+
working-directory: docs-repo
|
|
92
|
+
run: |
|
|
93
|
+
set -euo pipefail
|
|
94
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
95
|
+
git add pages/api-references/genlayer-cli
|
|
96
|
+
git commit -m "docs(cli): sync API reference ${VERSION:-${{ env.VERSION }}}"
|
|
97
|
+
git push --set-upstream origin "$BRANCH"
|
|
98
|
+
echo "HAS_CHANGES=true" >> $GITHUB_ENV
|
|
99
|
+
else
|
|
100
|
+
echo "No changes to commit"
|
|
101
|
+
echo "HAS_CHANGES=false" >> $GITHUB_ENV
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
- name: Create PR in docs repo
|
|
105
|
+
if: env.HAS_CHANGES == 'true'
|
|
106
|
+
uses: peter-evans/create-pull-request@v6
|
|
107
|
+
with:
|
|
108
|
+
token: ${{ secrets.DOCS_REPO_TOKEN || secrets.GITHUB_TOKEN }}
|
|
109
|
+
path: docs-repo
|
|
110
|
+
commit-message: "docs(cli): sync API reference ${{ steps.version.outputs.value }}"
|
|
111
|
+
branch: ${{ env.BRANCH }}
|
|
112
|
+
title: "docs(cli): sync CLI API reference ${{ steps.version.outputs.value }}"
|
|
113
|
+
body: |
|
|
114
|
+
This PR updates the GenlayerCLI API Reference generated automatically from `${{ github.repository }}`.
|
|
115
|
+
|
|
116
|
+
- Version: `${{ steps.version.outputs.value }}`
|
|
117
|
+
- Source commit: `${{ github.sha }}`
|
|
118
|
+
- Trigger: `${{ github.event_name }}`
|
|
119
|
+
labels: documentation, cli
|
|
120
|
+
|
|
121
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.30.0 (2025-09-03)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* genlayercli api reference auto generated ([#247](https://github.com/yeagerai/genlayer-cli/issues/247)) ([b08c342](https://github.com/yeagerai/genlayer-cli/commit/b08c34218b9f02a1d8d7f1c0b532ab55cc4ca5af))
|
|
8
|
+
|
|
3
9
|
## 0.29.0 (2025-09-03)
|
|
4
10
|
|
|
5
11
|
### Features
|
package/dist/index.js
CHANGED
|
@@ -17856,7 +17856,7 @@ var require_semver2 = __commonJS({
|
|
|
17856
17856
|
import { program } from "commander";
|
|
17857
17857
|
|
|
17858
17858
|
// package.json
|
|
17859
|
-
var version = "0.
|
|
17859
|
+
var version = "0.30.0";
|
|
17860
17860
|
var package_default = {
|
|
17861
17861
|
name: "genlayer",
|
|
17862
17862
|
version,
|
|
@@ -17874,7 +17874,8 @@ var package_default = {
|
|
|
17874
17874
|
build: "cross-env NODE_ENV=production node esbuild.config.js",
|
|
17875
17875
|
release: "release-it --ci",
|
|
17876
17876
|
"release-beta": "release-it --ci --preRelease=beta",
|
|
17877
|
-
postinstall: "node ./scripts/postinstall.js"
|
|
17877
|
+
postinstall: "node ./scripts/postinstall.js",
|
|
17878
|
+
"docs:cli": "node scripts/generate-cli-docs.mjs"
|
|
17878
17879
|
},
|
|
17879
17880
|
repository: {
|
|
17880
17881
|
type: "git",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genlayer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "GenLayer Command Line Tool",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"build": "cross-env NODE_ENV=production node esbuild.config.js",
|
|
16
16
|
"release": "release-it --ci",
|
|
17
17
|
"release-beta": "release-it --ci --preRelease=beta",
|
|
18
|
-
"postinstall": "node ./scripts/postinstall.js"
|
|
18
|
+
"postinstall": "node ./scripts/postinstall.js",
|
|
19
|
+
"docs:cli": "node scripts/generate-cli-docs.mjs"
|
|
19
20
|
},
|
|
20
21
|
"repository": {
|
|
21
22
|
"type": "git",
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
function escapeMdx(text) {
|
|
8
|
+
if (!text) return '';
|
|
9
|
+
return String(text).replace(/</g, '<').replace(/>/g, '>');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function formatArg(arg) {
|
|
13
|
+
const base = arg.variadic ? `${arg.name}...` : arg.name;
|
|
14
|
+
return arg.required ? `<${base}>` : `[${base}]`;
|
|
15
|
+
}
|
|
16
|
+
function toSlug(text) {
|
|
17
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function makeCommandFilepath(commandPath) {
|
|
21
|
+
const parts = commandPath.split(' ');
|
|
22
|
+
if (parts.length === 1) return { relDir: '', filename: `${toSlug(parts[0])}.mdx` };
|
|
23
|
+
return { relDir: parts.slice(0, -1).map(toSlug).join('/'), filename: `${toSlug(parts[parts.length - 1])}.mdx` };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderOptionsTable(options) {
|
|
27
|
+
if (!options.length) return 'No options.\n';
|
|
28
|
+
const rows = options
|
|
29
|
+
.map((o) => `| ${escapeMdx(o.short ?? '')} | ${escapeMdx(o.long ?? '')} | ${escapeMdx(o.description ?? '')} | ${o.required ? 'Yes' : 'No'} | ${o.defaultValue === undefined ? '' : `\`${escapeMdx(String(o.defaultValue))}\``} |`)
|
|
30
|
+
.join('\n');
|
|
31
|
+
return ['| Short | Long | Description | Required | Default |', '| --- | --- | --- | :---: | --- |', rows].join('\n');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderArgsList(args) {
|
|
35
|
+
if (!args.length) return 'No positional arguments.\n';
|
|
36
|
+
return args.map((a) => `- \`${formatArg(a)}\``).join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function generatePageForCommand(help, programName, commandPath) {
|
|
40
|
+
const { description, usage, args, options, subcommands } = help;
|
|
41
|
+
const title = commandPath || programName;
|
|
42
|
+
const header = `---\ntitle: ${escapeMdx(title)}\n---`;
|
|
43
|
+
const parts = [header];
|
|
44
|
+
if (description) parts.push('', description);
|
|
45
|
+
if (usage) parts.push('', '### Usage', '', `\`${usage}\``);
|
|
46
|
+
if (args && args.length) parts.push('', '### Arguments', '', renderArgsList(args));
|
|
47
|
+
parts.push('', '### Options', '', renderOptionsTable(options || []));
|
|
48
|
+
if (subcommands && subcommands.length) {
|
|
49
|
+
parts.push('', '### Subcommands', '');
|
|
50
|
+
for (const sc of subcommands) {
|
|
51
|
+
parts.push(`- \`${programName} ${sc.name}\` — ${escapeMdx(sc.description ?? '')}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const body = parts.join('\n').trim() + '\n';
|
|
55
|
+
const { relDir, filename } = makeCommandFilepath(commandPath || programName);
|
|
56
|
+
return { relDir, filename, content: body };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function generateIndexPage(rootHelp, programName, pkgVersion, pkgDescription) {
|
|
60
|
+
const title = `${programName} Commands`;
|
|
61
|
+
const header = `---\ntitle: ${escapeMdx(title)}\n---`;
|
|
62
|
+
const intro = rootHelp.description || pkgDescription || '';
|
|
63
|
+
const lines = [header, '', intro, `Version: \`${pkgVersion}\``, '', '### Command List', ''];
|
|
64
|
+
for (const sc of rootHelp.subcommands || []) {
|
|
65
|
+
lines.push(`- \`${programName} ${sc.name}\` — ${escapeMdx(sc.description ?? '')}`);
|
|
66
|
+
}
|
|
67
|
+
lines.push('', '---', '', 'This reference is auto-generated. Do not edit manually.');
|
|
68
|
+
return { relDir: '', filename: 'index.mdx', content: lines.join('\n') + '\n' };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runHelp(args) {
|
|
72
|
+
const res = spawnSync(process.execPath, ['dist/index.js', ...args, '--help'], {
|
|
73
|
+
encoding: 'utf8',
|
|
74
|
+
timeout: 30000,
|
|
75
|
+
});
|
|
76
|
+
if ((res.status !== 0 || res.error) && res.stdout.trim() === '') {
|
|
77
|
+
const reason = res.error?.message || res.stderr || `exitCode=${res.status}`;
|
|
78
|
+
throw new Error(`Failed to run help for: ${args.join(' ')} (${reason})`);
|
|
79
|
+
}
|
|
80
|
+
return res.stdout;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function parseHelp(text, programName, commandPath) {
|
|
84
|
+
const lines = text.split(/\r?\n/);
|
|
85
|
+
let description = '';
|
|
86
|
+
let usage = '';
|
|
87
|
+
const options = [];
|
|
88
|
+
const subcommands = [];
|
|
89
|
+
const args = [];
|
|
90
|
+
|
|
91
|
+
// Accumulate description between the first blank after Usage and before Options/Commands
|
|
92
|
+
let inOptions = false;
|
|
93
|
+
let inCommands = false;
|
|
94
|
+
|
|
95
|
+
// Usage
|
|
96
|
+
const usageIdx = lines.findIndex((l) => l.startsWith('Usage:'));
|
|
97
|
+
if (usageIdx !== -1) {
|
|
98
|
+
const usageLine = lines[usageIdx];
|
|
99
|
+
// Replace program binary name (index) by programName
|
|
100
|
+
const afterColon = usageLine.replace(/^Usage:\s*/, '');
|
|
101
|
+
const replaced = afterColon.replace(/^\S+/, programName);
|
|
102
|
+
usage = `$ ${replaced}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Description
|
|
106
|
+
for (let i = usageIdx + 1; i < lines.length; i += 1) {
|
|
107
|
+
const l = lines[i];
|
|
108
|
+
if (l.trim() === '') continue;
|
|
109
|
+
if (l.startsWith('Options:') || l.startsWith('Commands:')) break;
|
|
110
|
+
description += (description ? '\n' : '') + l.trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Parse sections
|
|
114
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
115
|
+
const l = lines[i];
|
|
116
|
+
if (l.startsWith('Options:')) { inOptions = true; inCommands = false; continue; }
|
|
117
|
+
if (l.startsWith('Commands:')) { inCommands = true; inOptions = false; continue; }
|
|
118
|
+
if (/^\s*$/.test(l)) continue;
|
|
119
|
+
|
|
120
|
+
if (inOptions) {
|
|
121
|
+
// e.g., " -V, --version output the version number"
|
|
122
|
+
const m = l.match(/^\s*(-\w)?,?\s*(--[\w-]+)?\s{2,}(.+)$/);
|
|
123
|
+
if (m) {
|
|
124
|
+
const short = m[1] || '';
|
|
125
|
+
const long = m[2] || '';
|
|
126
|
+
const desc = m[3] || '';
|
|
127
|
+
options.push({ short, long, description: desc, required: false });
|
|
128
|
+
}
|
|
129
|
+
} else if (inCommands) {
|
|
130
|
+
// e.g., " deploy [options] Deploy intelligent contracts"
|
|
131
|
+
const m = l.match(/^\s*([\w-]+)(?:\s<[^>]+>|\s\[[^\]]+\])*\s{2,}(.+)$/);
|
|
132
|
+
if (m) {
|
|
133
|
+
const cmdToken = m[1];
|
|
134
|
+
const desc = m[2] || '';
|
|
135
|
+
const name = cmdToken.trim();
|
|
136
|
+
if (name !== 'help') {
|
|
137
|
+
subcommands.push({ name, description: desc });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Derive args from usage (after commandPath)
|
|
144
|
+
if (usage) {
|
|
145
|
+
const usageCmd = usage.replace(/^`?\$\s+/, '').replace(/`?$/, '');
|
|
146
|
+
const tokens = usageCmd.split(/\s+/);
|
|
147
|
+
// find starting index of commandPath tokens
|
|
148
|
+
const cmdTokens = (commandPath ? `${programName} ${commandPath}` : programName).split(' ');
|
|
149
|
+
const start = tokens.findIndex((t, idx) => tokens.slice(idx, idx + cmdTokens.length).join(' ') === cmdTokens.join(' '));
|
|
150
|
+
const after = start >= 0 ? tokens.slice(start + cmdTokens.length) : [];
|
|
151
|
+
for (const t of after) {
|
|
152
|
+
if (t === '[options]') continue;
|
|
153
|
+
const m = t.match(/^<(.*)>$/) || t.match(/^\[(.*)\]$/);
|
|
154
|
+
if (m) {
|
|
155
|
+
const variadic = m[1].endsWith('...');
|
|
156
|
+
const name = variadic ? m[1].slice(0, -3) : m[1];
|
|
157
|
+
const required = t.startsWith('<');
|
|
158
|
+
args.push({ name, variadic, required });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return { description, usage, options, subcommands, args };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function ensureDir(dir) {
|
|
167
|
+
await fs.mkdir(dir, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function writePages(root, pages) {
|
|
171
|
+
for (const page of pages) {
|
|
172
|
+
const dir = path.join(root, page.relDir);
|
|
173
|
+
await ensureDir(dir);
|
|
174
|
+
const fullpath = path.join(dir, page.filename);
|
|
175
|
+
await fs.writeFile(fullpath, page.content, 'utf8');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function rmrf(dir) {
|
|
180
|
+
try {
|
|
181
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
182
|
+
} catch {}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function readPackageInfo() {
|
|
186
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
187
|
+
const pkgPath = path.join(here, '..', 'package.json');
|
|
188
|
+
const raw = await fs.readFile(pkgPath, 'utf8');
|
|
189
|
+
const json = JSON.parse(raw);
|
|
190
|
+
return { version: json.version, description: json.description };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function main() {
|
|
194
|
+
const { version: pkgVersion, description: pkgDescription } = await readPackageInfo();
|
|
195
|
+
const programName = 'genlayer';
|
|
196
|
+
|
|
197
|
+
// Ensure CLI is built before attempting to read help output
|
|
198
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
199
|
+
const cliPath = path.join(here, '..', 'dist', 'index.js');
|
|
200
|
+
try {
|
|
201
|
+
await fs.access(cliPath);
|
|
202
|
+
} catch {
|
|
203
|
+
throw new Error('CLI not built. Please run "npm run build" first.');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const rootHelpText = runHelp([]);
|
|
207
|
+
const rootHelp = parseHelp(rootHelpText, programName, '');
|
|
208
|
+
|
|
209
|
+
const outputDirFromEnv = process.env.DOCS_OUTPUT_DIR;
|
|
210
|
+
const clean = (process.env.DOCS_CLEAN || '').toLowerCase() === 'true';
|
|
211
|
+
|
|
212
|
+
const outputs = [];
|
|
213
|
+
// filter out auto 'help' just in case
|
|
214
|
+
rootHelp.subcommands = (rootHelp.subcommands || []).filter((c) => c.name !== 'help');
|
|
215
|
+
outputs.push(generateIndexPage(rootHelp, programName, pkgVersion, pkgDescription));
|
|
216
|
+
|
|
217
|
+
// BFS through subcommands by invoking help for each
|
|
218
|
+
const queue = [...(rootHelp.subcommands || [])].map((c) => ({ path: c.name }));
|
|
219
|
+
while (queue.length) {
|
|
220
|
+
const { path: cmdPath } = queue.shift();
|
|
221
|
+
const helpText = runHelp(cmdPath.split(' '));
|
|
222
|
+
const help = parseHelp(helpText, programName, cmdPath);
|
|
223
|
+
outputs.push(generatePageForCommand(help, programName, cmdPath));
|
|
224
|
+
for (const sc of help.subcommands || []) {
|
|
225
|
+
queue.push({ path: `${cmdPath} ${sc.name}` });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const defaultOut = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'docs', 'api-references');
|
|
230
|
+
const rootOut = outputDirFromEnv ? outputDirFromEnv : defaultOut;
|
|
231
|
+
if (clean) await rmrf(rootOut);
|
|
232
|
+
await writePages(rootOut, outputs);
|
|
233
|
+
|
|
234
|
+
const meta = {};
|
|
235
|
+
for (const c of (rootHelp.subcommands || []).map((c) => toSlug(c.name))) meta[c] = c;
|
|
236
|
+
await fs.writeFile(path.join(rootOut, '_meta.json'), JSON.stringify(meta, null, 2), 'utf8');
|
|
237
|
+
|
|
238
|
+
console.log(`Generated ${outputs.length} pages at ${rootOut}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
main().catch((err) => {
|
|
242
|
+
console.error(err);
|
|
243
|
+
process.exit(1);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
|