Files
docs/packages/cli/src/index.ts
zeekay f3b95cca11 merge: upstream/main (preserve Hanzo brand, 334 commits)
# Conflicts:
#	apps/docs/app/(home)/sponsors/data.tsx
#	apps/docs/app/(home)/uwu.tsx
#	apps/docs/app/og/[...slug]/generate.tsx
#	apps/docs/app/static.json/route.ts
#	apps/docs/content/blog/customise-ui.mdx
#	apps/docs/content/blog/mdx-v10-summary.mdx
#	apps/docs/content/blog/openapi-v9.mdx
#	apps/docs/content/blog/v15.mdx
#	apps/docs/content/blog/v16-2.mdx
#	apps/docs/content/docs/(framework)/deploying/static.mdx
#	apps/docs/content/docs/(framework)/integrations/content/custom.mdx
#	apps/docs/content/docs/(framework)/integrations/openapi/generate-files.mdx
#	apps/docs/content/docs/(framework)/integrations/openapi/server.mdx
#	apps/docs/content/docs/(framework)/integrations/story/client.story.tsx
#	apps/docs/content/docs/(framework)/integrations/story/index.mdx
#	apps/docs/content/docs/(framework)/integrations/story/next.mdx
#	apps/docs/content/docs/(framework)/search/orama.mdx
#	apps/docs/content/docs/(framework)/what-is-fumadocs.mdx
#	apps/docs/content/docs/cli/index.mdx
#	apps/docs/content/docs/headless/mdx/headings.mdx
#	apps/docs/content/docs/headless/mdx/rehype-code.mdx
#	apps/docs/content/docs/headless/mdx/remark-image.mdx
#	apps/docs/content/docs/headless/source-api/plugins.mdx
#	apps/docs/content/docs/mdx/(integrations)/loader/node.mdx
#	apps/docs/content/docs/mdx/global.mdx
#	apps/docs/content/docs/mdx/index.mdx
#	apps/docs/content/docs/ui/components/banner.mdx
#	apps/docs/content/docs/ui/components/graph-view.mdx
#	apps/docs/content/docs/ui/layouts/flux.mdx
#	apps/docs/content/docs/ui/layouts/home-layout.mdx
#	apps/docs/content/docs/ui/layouts/root-provider.mdx
#	apps/docs/content/docs/ui/theme.mdx
#	apps/docs/eslint.config.mjs
#	apps/docs/scripts/preload.ts
#	apps/docs/scripts/update-orama-index.ts
#	examples/openapi/README.md
#	examples/openapi/scripts/generate-docs.ts
#	examples/react-router-i18n/scripts/preload.ts
#	examples/tanstack-start-story/src/components/callout/story-client.tsx
#	packages/base-ui/scripts/compile-inline.utils.ts
#	packages/cli/src/build/index.ts
#	packages/core/src/content/md/frontmatter.ts
#	packages/create-app/scripts/update-git-repo.js
#	packages/create-app/scripts/update-git-repo.sh
#	packages/mdx-runtime/eslint.config.mjs
#	packages/openapi/scripts/compile-inline.utils.ts
#	packages/openapi/src/server/create.ts
#	packages/openapi/src/ui/full.tsx
#	packages/openapi/src/utils/process-document.ts
#	packages/press/waku.config.ts
#	packages/radix-ui/scripts/compile-inline.utils.ts
2026-06-02 09:55:12 -07:00

117 lines
4.1 KiB
JavaScript

#!/usr/bin/env node
import fs from 'node:fs/promises';
import path from 'node:path';
import { Command } from 'commander';
import picocolors from 'picocolors';
import { createOrLoadConfig, initConfig } from '@/config';
import { type JsonTreeNode, treeToJavaScript, treeToMdx } from '@/commands/file-tree';
import { runTree } from '@/utils/file-tree/run-tree';
import packageJson from '../package.json';
import { customise } from '@/commands/customise';
import { add } from '@/commands/add';
import { exportEpub } from '@/commands/export-epub';
import { HttpRegistryConnector, LocalRegistryConnector } from 'fuma-cli/registry/connector';
const program = new Command().option('--config <string>');
program
.name('hanzo-docs')
.description('CLI to setup Hanzo Docs, init a config')
.version(packageJson.version)
.action(async () => {
if (await initConfig()) {
console.log(picocolors.green('Initialized a `./cli.json` config file.'));
} else {
console.log(picocolors.redBright('A config file already exists.'));
}
});
program
.command('customise')
.alias('customize')
.description('simple way to customise layouts with Hanzo Docs UI')
.option('--dir <string>', 'the root url or directory to resolve registry')
.action(async (options: { config?: string; dir?: string }) => {
const config = await createOrLoadConfig(options.config);
await customise(config, createClientFromDir(options.dir));
});
const dirShortcuts: Record<string, string> = {
':preview': 'https://preview.hanzo.ai/docs/registry',
':dev': 'http://localhost:3000/registry',
};
program
.command('add')
.description('add a new component to your docs')
.argument('[components...]', 'components to download')
.option('--dir <string>', 'the root url or directory to resolve registry')
.action(async (input: string[], options: { config?: string; dir?: string }) => {
const config = await createOrLoadConfig(options.config);
const client = createClientFromDir(options.dir);
await add(input, client, config);
});
const exportCmd = program.command('export').description('export documentation to various formats');
exportCmd
.command('epub')
.description('export documentation to EPUB format (run after production build)')
.requiredOption('--framework <name>', 'React framework: next, tanstack-start, react-router, waku')
.option('--output <path>', 'output file path', 'docs.epub')
.option('--scaffold-only', 'only scaffold the EPUB route, do not copy')
.action(async (options: { output?: string; framework: string; scaffoldOnly?: boolean }) => {
await exportEpub({
output: options.output,
framework: options.framework,
scaffoldOnly: options.scaffoldOnly,
});
});
program
.command('tree')
.argument('[json_or_args]', 'JSON output of `tree` command or arguments for the `tree` command')
.argument('[output]', 'output path of file')
.option('--js', 'output as JavaScript file')
.option('--no-root', 'remove the root node')
.option('--import-name <name>', 'where to import components (JS only)')
.action(
async (
str: string | undefined,
output: string | undefined,
{ js, root, importName }: { js: boolean; root: boolean; importName?: string },
) => {
const jsExtensions = ['.js', '.tsx', '.jsx'];
const noRoot = !root;
let nodes: JsonTreeNode[];
try {
nodes = JSON.parse(str ?? '') as JsonTreeNode[];
} catch {
nodes = await runTree(str ?? './');
}
const out =
js || (output && jsExtensions.includes(path.extname(output)))
? treeToJavaScript(nodes, noRoot, importName)
: treeToMdx(nodes, noRoot);
if (output) {
await fs.mkdir(path.dirname(output), { recursive: true });
await fs.writeFile(output, out);
} else {
console.log(out);
}
},
);
function createClientFromDir(dir = 'https://hanzo.ai/docs/registry', config: LoadedConfig) {
if (dir in dirShortcuts) dir = dirShortcuts[dir];
return dir.startsWith('http://') || dir.startsWith('https://')
? new HttpRegistryConnector(dir)
: new LocalRegistryConnector(dir);
}
program.parse();