import { getMigrationDoc } from './commands/migration'; import { writeOutput } from './utils/output'; const HELP_TEXT = `Usage: blok-cli [options] Options: --convert-html Convert legacy HTML from stdin to Blok JSON (stdout) --convert-gdocs Convert Google Docs HTML from stdin to Blok JSON (stdout) --migration Output the EditorJS to Blok migration guide (LLM-friendly) --output Write output to a file instead of stdout --help Show this help message Examples: npx @bloklabs/cli --convert-html < article.html npx @bloklabs/cli --convert-html < article.html --output article.json npx @bloklabs/cli --convert-gdocs < gdocs-export.html npx @bloklabs/cli --convert-gdocs < gdocs-export.html --output doc.json npx @bloklabs/cli --migration npx @bloklabs/cli --migration | pbcopy npx @bloklabs/cli --migration --output migration-guide.md `; const parseArgs = (argv: string[]): { command: string | null; output?: string } => { if (argv.includes('--help')) { return { command: 'help' }; } if (argv.includes('--convert-html')) { const outputIndex = argv.indexOf('--output'); const output = outputIndex !== -1 ? argv[outputIndex + 1] : undefined; return { command: 'convert-html', output }; } if (argv.includes('--convert-gdocs')) { const outputIndex = argv.indexOf('--output'); const output = outputIndex !== -1 ? argv[outputIndex + 1] : undefined; return { command: 'convert-gdocs', output }; } if (argv.includes('--migration')) { const outputIndex = argv.indexOf('--output'); const output = outputIndex !== -1 ? argv[outputIndex + 1] : undefined; return { command: 'migration', output }; } return { command: null }; }; export const run = async (argv: string[], version: string): Promise => { const { command, output } = parseArgs(argv); switch (command) { case 'convert-html': { const jsdom = await import('jsdom'); const dom = new jsdom.JSDOM(''); globalThis.DOMParser = dom.window.DOMParser; globalThis.Node = dom.window.Node; const { convertHtml } = await import('./commands/convert-html/index'); const fs = await import('node:fs'); // fd 0, not '/dev/stdin': reopening the path fails with ENXIO on Linux when // the writer has already closed the pipe (any non-shell caller passing input). const html = fs.readFileSync(0, 'utf-8'); const json = convertHtml(html); writeOutput(json, output); break; } case 'convert-gdocs': { const jsdom = await import('jsdom'); const dom = new jsdom.JSDOM(''); globalThis.DOMParser = dom.window.DOMParser; globalThis.Node = dom.window.Node; (globalThis as Record).document = dom.window.document; const { convertGdocs } = await import('./commands/convert-gdocs/index'); const fs = await import('node:fs'); // fd 0, not '/dev/stdin': reopening the path fails with ENXIO on Linux when // the writer has already closed the pipe (any non-shell caller passing input). const html = fs.readFileSync(0, 'utf-8'); const json = convertGdocs(html); writeOutput(json, output); break; } case 'migration': { const content = getMigrationDoc(version); writeOutput(content, output); break; } case 'help': case null: process.stdout.write(HELP_TEXT); break; } };