From 5968bcfb103c3ca748e1a61f064594cf55d57731 Mon Sep 17 00:00:00 2001 From: Fabian Rodriguez Date: Thu, 17 Oct 2024 15:10:15 +0200 Subject: [PATCH 1/4] feat: WIP generate insomnia-inso docs from source Add a script that generates the reference docs for insomnia-inso from the source code. Commander exposes commands, options and descriptions which we can use to generate the markdown files. This is a WIP to start a convo and an initial implementation, the script doesn't work as it is because `cli.ts` doesn't export `program` and `version`. --- packages/insomnia-inso/src/scripts/docs.ts | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 packages/insomnia-inso/src/scripts/docs.ts diff --git a/packages/insomnia-inso/src/scripts/docs.ts b/packages/insomnia-inso/src/scripts/docs.ts new file mode 100644 index 00000000000..ddc123bc33a --- /dev/null +++ b/packages/insomnia-inso/src/scripts/docs.ts @@ -0,0 +1,125 @@ +import path from 'node:path'; + +import * as commander from 'commander'; +import fs from 'fs'; + +import { program, version } from '../cli'; + +const DOCS_DIR = path.join(__dirname, `../../../../reference/insomnia-inso/${version}`); + +function writeMarkdownFile(fileName: string, content: string): void { + const outputPath = path.join(DOCS_DIR, fileName); + fs.writeFileSync(outputPath, content); +} + +function generateOptionsMarkdown(options: readonly commander.Option[], title: string): string { + if (options.length === 0) { + return ''; + } + + const optionList = options.map(option => `- \`${option.flags}\`: ${option.description}\n`).join(''); + return `\n## ${title}\n\n${optionList}`; +} + +function generateSubcommandsMarkdown(commandName: string, subcommands: { name: string; description: string }[]): string { + if (subcommands.length === 0) { + return ''; + } + + let subcommandsMarkdown = '\n## Subcommands\n\n'; + subcommands.forEach(sub => { + const subCommandFileName = `${commandName.replace(/\s+/g, '_')}_${sub.name.replace(/\s+/g, '_')}.md`; + subcommandsMarkdown += `- [\`${commandName} ${sub.name}\`](${generateFileURL(subCommandFileName)}): ${sub.description}\n`; + }); + + return subcommandsMarkdown; +} + +function generateCommandMarkdownContent(command: commander.Command, parentName?: string): string { + const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); + const usage = command.usage() || '[options]'; + + let commandMarkdown = `# ${commandName}\n\n`; + commandMarkdown += `## Command Description\n\n${command.description()}\n\n`; + commandMarkdown += `## Syntax\n\n\`${commandName} ${usage}\`\n`; + + if (command.options.length > 0) { + commandMarkdown += generateOptionsMarkdown(command.options, 'Local Flags'); + } + + commandMarkdown += generateOptionsMarkdown(program.options, 'Global Flags'); + commandMarkdown += generateSubcommandsMarkdown(commandName, command.commands.map(sub => ({ + name: sub.name(), + description: sub.description() || 'No description available', + }))); + + return commandMarkdown; +} + +function generateCommandMarkdown(command: commander.Command, parentName?: string): { name: string; fileName: string; description: string; subcommands: readonly commander.Command[] } { + const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); + const fileName = `${commandName.replace(/\s+/g, '_')}.md`; + + const commandMarkdown = generateCommandMarkdownContent(command, parentName); + writeMarkdownFile(fileName, commandMarkdown); + + return { + name: commandName, + fileName, + description: command.description() || 'No description available', + subcommands: command.commands, + }; +} + +function generateFileURL(fileName: string): string { + return `/insomnia-inso/${fileName.replace('.md', '')}/`; +} + +function generateIndexContent(globalOptions: readonly commander.Option[], allCommands: { name: string; description: string; fileName: string; subcommands: any[] }[]): string { + let indexContent = '# CLI Documentation \n'; + + indexContent += generateOptionsMarkdown(globalOptions, 'Global Flags'); + + indexContent += '\n## Commands\n\n'; + allCommands.forEach(({ name, description, fileName }) => { + indexContent += `- [\`${name}\`](${generateFileURL(fileName)}): ${description}\n`; + }); + + allCommands.forEach(({ name, subcommands }) => { + indexContent += generateSubcommandsMarkdown(name, subcommands); + }); + + return indexContent; +} + +export function generateDocumentation(): void { + if (!fs.existsSync(DOCS_DIR)) { + fs.mkdirSync(DOCS_DIR, { recursive: true }); + } + + const allCommands: any[] = []; + + program.commands.forEach(command => { + const commandData = generateCommandMarkdown(command, ''); + + allCommands.push({ + name: commandData.name, + description: commandData.description, + fileName: commandData.fileName, + subcommands: commandData.subcommands.map(sub => ({ + name: sub.name(), + description: sub.description() || 'No description available', + fileName: `${commandData.name.replace(/\s+/g, '_')}_${sub.name().replace(/\s+/g, '_')}.md`, + })), + }); + + commandData.subcommands.forEach(sub => { + generateCommandMarkdown(sub, commandData.name); + }); + }); + + const indexContent = generateIndexContent(program.options, allCommands); + writeMarkdownFile('index.md', indexContent); +} + +generateDocumentation(); From fb6108f97f2b61eab08f3b7f047d3116b68adfc3 Mon Sep 17 00:00:00 2001 From: jackkav Date: Wed, 23 Oct 2024 15:33:02 +0200 Subject: [PATCH 2/4] wire up program --- packages/insomnia-inso/src/cli.ts | 7 +++++++ packages/insomnia-inso/src/scripts/docs.ts | 18 ++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/insomnia-inso/src/cli.ts b/packages/insomnia-inso/src/cli.ts index fba4ca5555f..4c388627c31 100644 --- a/packages/insomnia-inso/src/cli.ts +++ b/packages/insomnia-inso/src/cli.ts @@ -26,6 +26,7 @@ import { loadEnvironment, promptEnvironment } from './db/models/environment'; import { loadTestSuites, promptTestSuites } from './db/models/unit-test-suite'; import { matchIdIsh } from './db/models/util'; import { loadWorkspace, promptWorkspace } from './db/models/workspace'; +import { generateCommandMarkdown, generateDocumentation } from './scripts/docs'; export interface GlobalOptions { ci: boolean; @@ -711,5 +712,11 @@ Test results:`); program.parseAsync(scriptArgs).catch(logErrorAndExit); }); + program.command('generate-docs') + .action(() => { + generateDocumentation(program); + return process.exit(1); + }); + program.parseAsync(args || process.argv).catch(logErrorAndExit); }; diff --git a/packages/insomnia-inso/src/scripts/docs.ts b/packages/insomnia-inso/src/scripts/docs.ts index ddc123bc33a..c82e24bde78 100644 --- a/packages/insomnia-inso/src/scripts/docs.ts +++ b/packages/insomnia-inso/src/scripts/docs.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import * as commander from 'commander'; import fs from 'fs'; -import { program, version } from '../cli'; +import { version } from '../../package.json'; const DOCS_DIR = path.join(__dirname, `../../../../reference/insomnia-inso/${version}`); @@ -35,7 +35,7 @@ function generateSubcommandsMarkdown(commandName: string, subcommands: { name: s return subcommandsMarkdown; } -function generateCommandMarkdownContent(command: commander.Command, parentName?: string): string { +function generateCommandMarkdownContent(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): string { const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); const usage = command.usage() || '[options]'; @@ -47,7 +47,7 @@ function generateCommandMarkdownContent(command: commander.Command, parentName?: commandMarkdown += generateOptionsMarkdown(command.options, 'Local Flags'); } - commandMarkdown += generateOptionsMarkdown(program.options, 'Global Flags'); + commandMarkdown += generateOptionsMarkdown(programOptions, 'Global Flags'); commandMarkdown += generateSubcommandsMarkdown(commandName, command.commands.map(sub => ({ name: sub.name(), description: sub.description() || 'No description available', @@ -56,11 +56,11 @@ function generateCommandMarkdownContent(command: commander.Command, parentName?: return commandMarkdown; } -function generateCommandMarkdown(command: commander.Command, parentName?: string): { name: string; fileName: string; description: string; subcommands: readonly commander.Command[] } { +export function generateCommandMarkdown(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): { name: string; fileName: string; description: string; subcommands: readonly commander.Command[] } { const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); const fileName = `${commandName.replace(/\s+/g, '_')}.md`; - const commandMarkdown = generateCommandMarkdownContent(command, parentName); + const commandMarkdown = generateCommandMarkdownContent(command, programOptions, parentName); writeMarkdownFile(fileName, commandMarkdown); return { @@ -92,7 +92,7 @@ function generateIndexContent(globalOptions: readonly commander.Option[], allCom return indexContent; } -export function generateDocumentation(): void { +export function generateDocumentation(program: commander.Command): void { if (!fs.existsSync(DOCS_DIR)) { fs.mkdirSync(DOCS_DIR, { recursive: true }); } @@ -100,7 +100,7 @@ export function generateDocumentation(): void { const allCommands: any[] = []; program.commands.forEach(command => { - const commandData = generateCommandMarkdown(command, ''); + const commandData = generateCommandMarkdown(command, program.options, ''); allCommands.push({ name: commandData.name, @@ -114,12 +114,10 @@ export function generateDocumentation(): void { }); commandData.subcommands.forEach(sub => { - generateCommandMarkdown(sub, commandData.name); + generateCommandMarkdown(sub, program.options, commandData.name); }); }); const indexContent = generateIndexContent(program.options, allCommands); writeMarkdownFile('index.md', indexContent); } - -generateDocumentation(); From 4da51aee46c36e0eddac5021a23cba152755e31c Mon Sep 17 00:00:00 2001 From: jackkav Date: Wed, 23 Oct 2024 15:44:07 +0200 Subject: [PATCH 3/4] simplify --- packages/insomnia-inso/src/cli.ts | 2 +- packages/insomnia-inso/src/scripts/docs.ts | 47 +++++++--------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/packages/insomnia-inso/src/cli.ts b/packages/insomnia-inso/src/cli.ts index 4c388627c31..d596abbe95c 100644 --- a/packages/insomnia-inso/src/cli.ts +++ b/packages/insomnia-inso/src/cli.ts @@ -26,7 +26,7 @@ import { loadEnvironment, promptEnvironment } from './db/models/environment'; import { loadTestSuites, promptTestSuites } from './db/models/unit-test-suite'; import { matchIdIsh } from './db/models/util'; import { loadWorkspace, promptWorkspace } from './db/models/workspace'; -import { generateCommandMarkdown, generateDocumentation } from './scripts/docs'; +import { generateDocumentation } from './scripts/docs'; export interface GlobalOptions { ci: boolean; diff --git a/packages/insomnia-inso/src/scripts/docs.ts b/packages/insomnia-inso/src/scripts/docs.ts index c82e24bde78..cb24b2e7c86 100644 --- a/packages/insomnia-inso/src/scripts/docs.ts +++ b/packages/insomnia-inso/src/scripts/docs.ts @@ -5,7 +5,7 @@ import fs from 'fs'; import { version } from '../../package.json'; -const DOCS_DIR = path.join(__dirname, `../../../../reference/insomnia-inso/${version}`); +const DOCS_DIR = path.join(__dirname, `../reference/insomnia-inso/${version}`); function writeMarkdownFile(fileName: string, content: string): void { const outputPath = path.join(DOCS_DIR, fileName); @@ -17,8 +17,10 @@ function generateOptionsMarkdown(options: readonly commander.Option[], title: st return ''; } - const optionList = options.map(option => `- \`${option.flags}\`: ${option.description}\n`).join(''); - return `\n## ${title}\n\n${optionList}`; + return ` +## ${title} + +${options.map(option => `- \`${option.flags}\`: ${option.description}\n`).join('')}`; } function generateSubcommandsMarkdown(commandName: string, subcommands: { name: string; description: string }[]): string { @@ -26,13 +28,10 @@ function generateSubcommandsMarkdown(commandName: string, subcommands: { name: s return ''; } - let subcommandsMarkdown = '\n## Subcommands\n\n'; - subcommands.forEach(sub => { - const subCommandFileName = `${commandName.replace(/\s+/g, '_')}_${sub.name.replace(/\s+/g, '_')}.md`; - subcommandsMarkdown += `- [\`${commandName} ${sub.name}\`](${generateFileURL(subCommandFileName)}): ${sub.description}\n`; - }); + return ` +## Subcommands - return subcommandsMarkdown; +${subcommands.map(sub => `- [\`${commandName} ${sub.name}\`](/insomnia-inso/${commandName.replace(/\s+/g, '_')}_${sub.name.replace(/\s+/g, '_')}/): ${sub.description}`).join('\n')}`; } function generateCommandMarkdownContent(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): string { @@ -71,27 +70,6 @@ export function generateCommandMarkdown(command: commander.Command, programOptio }; } -function generateFileURL(fileName: string): string { - return `/insomnia-inso/${fileName.replace('.md', '')}/`; -} - -function generateIndexContent(globalOptions: readonly commander.Option[], allCommands: { name: string; description: string; fileName: string; subcommands: any[] }[]): string { - let indexContent = '# CLI Documentation \n'; - - indexContent += generateOptionsMarkdown(globalOptions, 'Global Flags'); - - indexContent += '\n## Commands\n\n'; - allCommands.forEach(({ name, description, fileName }) => { - indexContent += `- [\`${name}\`](${generateFileURL(fileName)}): ${description}\n`; - }); - - allCommands.forEach(({ name, subcommands }) => { - indexContent += generateSubcommandsMarkdown(name, subcommands); - }); - - return indexContent; -} - export function generateDocumentation(program: commander.Command): void { if (!fs.existsSync(DOCS_DIR)) { fs.mkdirSync(DOCS_DIR, { recursive: true }); @@ -118,6 +96,11 @@ export function generateDocumentation(program: commander.Command): void { }); }); - const indexContent = generateIndexContent(program.options, allCommands); - writeMarkdownFile('index.md', indexContent); + writeMarkdownFile('index.md', `# CLI Documentation +${generateOptionsMarkdown(program.options, 'Global Flags')} +## Commands + +${allCommands.map(({ name, description, fileName }) => `- [\`${name}\`](/insomnia-inso/${fileName.replace('.md', '')}/): ${description}`).join('\n')} +${allCommands.map(({ name, subcommands }) => generateSubcommandsMarkdown(name, subcommands)).join('\n')} +`); } From 7618803fb89af884d603946ae496b0e3c86fc616 Mon Sep 17 00:00:00 2001 From: jackkav Date: Wed, 23 Oct 2024 16:06:36 +0200 Subject: [PATCH 4/4] normalise line endings in each function --- packages/insomnia-inso/src/scripts/docs.ts | 60 +++++++++------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/packages/insomnia-inso/src/scripts/docs.ts b/packages/insomnia-inso/src/scripts/docs.ts index cb24b2e7c86..f47146f4342 100644 --- a/packages/insomnia-inso/src/scripts/docs.ts +++ b/packages/insomnia-inso/src/scripts/docs.ts @@ -13,54 +13,39 @@ function writeMarkdownFile(fileName: string, content: string): void { } function generateOptionsMarkdown(options: readonly commander.Option[], title: string): string { - if (options.length === 0) { - return ''; - } - - return ` -## ${title} + return options.length ? `## ${title} -${options.map(option => `- \`${option.flags}\`: ${option.description}\n`).join('')}`; +${options.map(option => `- \`${option.flags}\`: ${option.description} +`).join('')} +` : ''; } function generateSubcommandsMarkdown(commandName: string, subcommands: { name: string; description: string }[]): string { - if (subcommands.length === 0) { - return ''; - } + return subcommands.length ? `## Subcommands - return ` -## Subcommands - -${subcommands.map(sub => `- [\`${commandName} ${sub.name}\`](/insomnia-inso/${commandName.replace(/\s+/g, '_')}_${sub.name.replace(/\s+/g, '_')}/): ${sub.description}`).join('\n')}`; +${subcommands.map(sub => `- [\`${commandName} ${sub.name}\`](/insomnia-inso/${commandName.replace(/\s+/g, '_')}_${sub.name.replace(/\s+/g, '_')}/): ${sub.description} +`).join('')} +` : ''; } -function generateCommandMarkdownContent(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): string { +export function generateCommandMarkdown(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): { name: string; fileName: string; description: string; subcommands: readonly commander.Command[] } { const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); - const usage = command.usage() || '[options]'; + const fileName = `${commandName.replace(/\s+/g, '_')}.md`; - let commandMarkdown = `# ${commandName}\n\n`; - commandMarkdown += `## Command Description\n\n${command.description()}\n\n`; - commandMarkdown += `## Syntax\n\n\`${commandName} ${usage}\`\n`; + writeMarkdownFile(fileName, `# ${commandName} - if (command.options.length > 0) { - commandMarkdown += generateOptionsMarkdown(command.options, 'Local Flags'); - } +## Command Description - commandMarkdown += generateOptionsMarkdown(programOptions, 'Global Flags'); - commandMarkdown += generateSubcommandsMarkdown(commandName, command.commands.map(sub => ({ - name: sub.name(), - description: sub.description() || 'No description available', - }))); +${command.description()} - return commandMarkdown; -} +## Syntax -export function generateCommandMarkdown(command: commander.Command, programOptions: readonly commander.Option[], parentName?: string): { name: string; fileName: string; description: string; subcommands: readonly commander.Command[] } { - const commandName = parentName ? `${parentName} ${command.name()}` : command.name(); - const fileName = `${commandName.replace(/\s+/g, '_')}.md`; +\`${commandName} ${command.usage() || '[options]'}\` - const commandMarkdown = generateCommandMarkdownContent(command, programOptions, parentName); - writeMarkdownFile(fileName, commandMarkdown); +${command.options.length > 0 ? generateOptionsMarkdown(command.options, 'Local Flags') : ''}${generateOptionsMarkdown(programOptions, 'Global Flags')}${generateSubcommandsMarkdown(commandName, command.commands.map(sub => ({ + name: sub.name(), + description: sub.description() || 'No description available', +})))}`); return { name: commandName, @@ -100,7 +85,8 @@ export function generateDocumentation(program: commander.Command): void { ${generateOptionsMarkdown(program.options, 'Global Flags')} ## Commands -${allCommands.map(({ name, description, fileName }) => `- [\`${name}\`](/insomnia-inso/${fileName.replace('.md', '')}/): ${description}`).join('\n')} -${allCommands.map(({ name, subcommands }) => generateSubcommandsMarkdown(name, subcommands)).join('\n')} -`); +${allCommands.map(({ name, description, fileName }) => `- [\`${name}\`](/insomnia-inso/${fileName.replace('.md', '')}/): ${description} +`).join('')} +${allCommands.map(({ name, subcommands }) => `${generateSubcommandsMarkdown(name, subcommands)} +`).join('')}`); }