-
Notifications
You must be signed in to change notification settings - Fork 0
TypeScript Rewrite: Help command #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
d4mation
wants to merge
16
commits into
ENG-219/app-bootstrap
Choose a base branch
from
ENG-219/command-help
base: ENG-219/app-bootstrap
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
9f7e179
ENG-219: Add help command
d4mation 54d4c41
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation 8cac5d5
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation 815a8df
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation 99bac23
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation a43bcfa
ENG-219: Use createTempProject in help tests for isolation
d4mation 81c1c59
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation 49c74b0
ENG-219: Add styled output to help command matching PHP version
d4mation db4a0ff
ENG-219: Add tests for help command styling and output utilities
d4mation 5c88d4d
ENG-219: Brought over output changes from ENG-219/command-info
d4mation ef24664
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation 55c4e4a
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation aed4456
ENG-219: Make help the default command when pup is run without arguments
d4mation e1b1247
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation fa2e61e
Merge branch 'ENG-219/app-bootstrap' into ENG-219/command-help
d4mation e4e6099
ENG-219: Merge app-bootstrap and update imports to .ts
d4mation File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| import type { Command } from 'commander'; | ||
| import chalk from 'chalk'; | ||
| import fs from 'fs-extra'; | ||
| import path from 'node:path'; | ||
| import { getDefaultsDir } from '../config.ts'; | ||
| import * as output from '../utils/output.ts'; | ||
|
|
||
| /** | ||
| * Prints the decorated banner and command list. | ||
| * | ||
| * @since TBD | ||
| * | ||
| * @param {string} contents - The raw markdown contents of commands.md. | ||
| * | ||
| * @returns {void} | ||
| */ | ||
| function printCommandList(contents: string): void { | ||
| const border = '*'.repeat(80); | ||
|
|
||
| output.writeln(border); | ||
| output.writeln('*'); | ||
| output.writeln(`* ${chalk.blue(`${chalk.magenta('P')}roduct ${chalk.magenta('U')}tility & ${chalk.magenta('P')}ackager`)}`); | ||
| output.writeln('* ' + '-'.repeat(78)); | ||
| output.writeln('* A CLI utility by StellarWP'); | ||
| output.writeln('*'); | ||
| output.writeln(border); | ||
|
|
||
| output.newline(); | ||
| output.writeln(`Run ${chalk.cyan('pup help <topic>')} for more information on a specific command.`); | ||
| output.newline(); | ||
|
|
||
| const lines = contents.split('\n'); | ||
| const commands: [string, string][] = []; | ||
| let currentCommand: string | null = null; | ||
|
|
||
| for (const line of lines) { | ||
| const headerMatch = line.match(/##+\s+`pup ([^`]+)`/); | ||
| if (headerMatch) { | ||
| currentCommand = headerMatch[1]; | ||
| continue; | ||
| } | ||
|
|
||
| if (currentCommand && !commands.find(([cmd]) => cmd === currentCommand)) { | ||
| const trimmed = line.trim(); | ||
| if (trimmed) { | ||
| const description = trimmed.replace(/`([^`]+)`/g, (_, code: string) => chalk.cyan(code)); | ||
| commands.push([currentCommand, description]); | ||
| currentCommand = null; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| commands.sort((a, b) => a[0].localeCompare(b[0])); | ||
|
|
||
| output.table( | ||
| ['Command', 'Description'], | ||
| commands.map(([cmd, desc]) => [chalk.yellow(cmd), desc]), | ||
| ); | ||
|
|
||
| output.newline(); | ||
| output.writeln(`For more documentation, head over to ${chalk.yellow('https://github.com/stellarwp/pup')}`); | ||
| } | ||
|
|
||
| /** | ||
| * Prints styled help for a specific command topic. | ||
| * | ||
| * @since TBD | ||
| * | ||
| * @param {string} topic - The command topic to show help for. | ||
| * @param {string} contents - The raw markdown contents of commands.md. | ||
| * | ||
| * @returns {boolean} Whether the topic was found. | ||
| */ | ||
| function printCommandHelp(topic: string, contents: string): boolean { | ||
| const lines = contents.split('\n'); | ||
| let started = false; | ||
| let didFirstLine = false; | ||
| let inCodeBlock = false; | ||
| let inArgTable = false; | ||
| let argHeaders: string[] = []; | ||
| let argRows: string[][] = []; | ||
|
|
||
| for (const line of lines) { | ||
| if (started) { | ||
| // Stop when we hit the next ## command section | ||
| if (/^##+\s+`pup /.test(line)) { | ||
| break; | ||
| } | ||
|
|
||
| // Code block toggle | ||
| if (/^```/.test(line)) { | ||
| inCodeBlock = !inCodeBlock; | ||
| output.writeln(chalk.green('.'.repeat(50))); | ||
| continue; | ||
| } | ||
|
|
||
| // Inside code block | ||
| if (inCodeBlock) { | ||
| if (/^#/.test(line)) { | ||
| output.writeln(chalk.green(line)); | ||
| } else { | ||
| output.writeln(chalk.cyan(line)); | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| // Apply inline formatting (strip links first so ANSI codes from chalk | ||
| // don't contain `[` characters that confuse the link regex) | ||
| let formatted = line; | ||
| formatted = formatted.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1'); | ||
| formatted = formatted.replace(/`([^`]+)`/g, (_, code: string) => chalk.cyan(code)); | ||
| formatted = formatted.replace(/\*\*([^*]+)\*\*/g, (_, bold: string) => chalk.red(bold)); | ||
|
|
||
| // Argument/option table handling | ||
| if (inArgTable) { | ||
| if (/^\| (Arg|Opt)/.test(formatted)) { | ||
| argHeaders = formatted.replace(/^\||\|$/g, '').split('|').map((s) => s.trim()); | ||
| continue; | ||
| } | ||
|
|
||
| if (/^\|--/.test(line)) { | ||
| continue; | ||
| } | ||
|
|
||
| if (/^\|/.test(line)) { | ||
| argRows.push(formatted.replace(/^\||\|$/g, '').split('|').map((s) => s.trim())); | ||
| continue; | ||
| } | ||
|
|
||
| // End of table | ||
| if (argHeaders.length > 0) { | ||
| inArgTable = false; | ||
| output.table(argHeaders, argRows); | ||
| argHeaders = []; | ||
| argRows = []; | ||
| } | ||
| } | ||
|
|
||
| // Sub-section headers (### or ####) | ||
| const sectionMatch = formatted.match(/^##(#+) (.+)/); | ||
| if (sectionMatch) { | ||
| const depth = sectionMatch[1].length; | ||
| const label = sectionMatch[2]; | ||
| output.section(`${'>'.repeat(depth)} ${label}:`); | ||
|
|
||
| if (/^##(#+ )(Arguments|`\.puprc` options)/.test(line)) { | ||
| inArgTable = true; | ||
| argHeaders = []; | ||
| argRows = []; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| output.writeln(formatted); | ||
|
|
||
| if (!didFirstLine) { | ||
| didFirstLine = true; | ||
| output.newline(); | ||
| } | ||
| } else { | ||
| const topicPattern = new RegExp(`^##+\\s+\`pup ${topic.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\``); | ||
| if (topicPattern.test(line)) { | ||
| output.title(`Help: ${chalk.cyan('pup ' + topic)}`); | ||
| started = true; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Flush any remaining argument table | ||
| if (inArgTable && argHeaders.length > 0) { | ||
| output.table(argHeaders, argRows); | ||
| } | ||
|
|
||
| return started; | ||
| } | ||
|
|
||
| /** | ||
| * Registers the `help` command with the CLI program. | ||
| * | ||
| * @since TBD | ||
| * | ||
| * @param {Command} program - The Commander.js program instance. | ||
| * | ||
| * @returns {void} | ||
| */ | ||
| export function registerHelpCommand(program: Command): void { | ||
| program | ||
| .command('help [topic]', { isDefault: true }) | ||
| .description('Shows help for pup.') | ||
| .action(async (topic?: string) => { | ||
| const docsDir = path.resolve(getDefaultsDir(), '..', 'docs'); | ||
| const commandsPath = path.join(docsDir, 'commands.md'); | ||
|
|
||
| if (!await fs.pathExists(commandsPath)) { | ||
| output.log('Help documentation not found.'); | ||
| return; | ||
| } | ||
|
|
||
| const contents = await fs.readFile(commandsPath, 'utf-8'); | ||
|
|
||
| if (!topic) { | ||
| printCommandList(contents); | ||
| return; | ||
| } | ||
|
|
||
| const normalizedTopic = topic.replace('pup ', '').replace('pup-', ''); | ||
|
|
||
| if (!printCommandHelp(normalizedTopic, contents)) { | ||
| output.error(`Unknown topic: ${topic}`); | ||
| } | ||
| }); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isDefault: trueis to replicate how in the PHP version,php puprunsphp pup helpby default.