From 0c5ef70cee57db16e4b98e8048716bb8571c557c Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Wed, 6 May 2026 15:18:52 -0700 Subject: [PATCH 1/9] fix: claude code's first pass at generating markdown --- messages/main.md | 6 +- package.json | 11 ++ src/commands/commandreference/generate.ts | 15 +- src/ditamap/command-helpers.ts | 100 ++++++++++ src/ditamap/command.ts | 81 +------- src/docs.ts | 44 ++--- src/generator-factory.ts | 119 ++++++++++++ src/markdown/cli-reference.ts | 50 +++++ src/markdown/command.ts | 183 ++++++++++++++++++ src/markdown/index.ts | 22 +++ src/markdown/markdown-base.ts | 42 ++++ src/markdown/root-index.ts | 36 ++++ src/markdown/topic-commands.ts | 40 ++++ src/markdown/topic-index.ts | 41 ++++ test/tmp-md/cli_reference.md | 14 ++ test/tmp-md/cli_reference_index.md | 5 + test/tmp-md/org/cli_reference_org.md | 16 ++ .../org/cli_reference_org_assign_permset.md | 42 ++++ ...cli_reference_org_assign_permsetlicense.md | 42 ++++ test/tmp-md/org/cli_reference_org_commands.md | 3 + .../org/cli_reference_org_create_user.md | 67 +++++++ .../org/cli_reference_org_display_user.md | 32 +++ .../cli_reference_org_generate_password.md | 65 +++++++ .../tmp-md/org/cli_reference_org_list_auth.md | 24 +++ .../org/cli_reference_org_list_users.md | 32 +++ .../cli_reference_org_login_access-token.md | 37 ++++ .../tmp-md/org/cli_reference_org_login_jwt.md | 63 ++++++ .../org/cli_reference_org_login_sfdx-url.md | 57 ++++++ .../tmp-md/org/cli_reference_org_login_web.md | 65 +++++++ test/tmp-md/org/cli_reference_org_logout.md | 52 +++++ test/unit/markdown.test.ts | 113 +++++++++++ 31 files changed, 1411 insertions(+), 108 deletions(-) create mode 100644 src/ditamap/command-helpers.ts create mode 100644 src/generator-factory.ts create mode 100644 src/markdown/cli-reference.ts create mode 100644 src/markdown/command.ts create mode 100644 src/markdown/index.ts create mode 100644 src/markdown/markdown-base.ts create mode 100644 src/markdown/root-index.ts create mode 100644 src/markdown/topic-commands.ts create mode 100644 src/markdown/topic-index.ts create mode 100644 test/tmp-md/cli_reference.md create mode 100644 test/tmp-md/cli_reference_index.md create mode 100644 test/tmp-md/org/cli_reference_org.md create mode 100644 test/tmp-md/org/cli_reference_org_assign_permset.md create mode 100644 test/tmp-md/org/cli_reference_org_assign_permsetlicense.md create mode 100644 test/tmp-md/org/cli_reference_org_commands.md create mode 100644 test/tmp-md/org/cli_reference_org_create_user.md create mode 100644 test/tmp-md/org/cli_reference_org_display_user.md create mode 100644 test/tmp-md/org/cli_reference_org_generate_password.md create mode 100644 test/tmp-md/org/cli_reference_org_list_auth.md create mode 100644 test/tmp-md/org/cli_reference_org_list_users.md create mode 100644 test/tmp-md/org/cli_reference_org_login_access-token.md create mode 100644 test/tmp-md/org/cli_reference_org_login_jwt.md create mode 100644 test/tmp-md/org/cli_reference_org_login_sfdx-url.md create mode 100644 test/tmp-md/org/cli_reference_org_login_web.md create mode 100644 test/tmp-md/org/cli_reference_org_logout.md create mode 100644 test/unit/markdown.test.ts diff --git a/messages/main.md b/messages/main.md index 60b9bd1c..507115e9 100644 --- a/messages/main.md +++ b/messages/main.md @@ -28,7 +28,11 @@ fail the command if there are any warnings # flags.ditamap-suffix.summary -unique suffix to append to generated ditamap +unique suffix to append to generated DITA files + +# flags.output-format.summary + +output format for generated documentation; 'dita' (default) generates DITA XML files, 'markdown' generates Markdown files # flags.config-path.summary diff --git a/package.json b/package.json index bc553255..4bf22ca8 100644 --- a/package.json +++ b/package.json @@ -196,6 +196,17 @@ "messages/**/*.md" ], "output": [] + }, + "test:command-reference-markdown": { + "command": "node --loader ts-node/esm --no-warnings=ExperimentalWarning \"./bin/dev.js\" commandreference generate --plugins auth --plugins user --output-format markdown --outputdir test/tmp-md", + "files": [ + "src/**/*.ts", + "messages/**", + "package.json" + ], + "output": [ + "test/tmp-md" + ] } } } diff --git a/src/commands/commandreference/generate.ts b/src/commands/commandreference/generate.ts index af882482..341aca0a 100644 --- a/src/commands/commandreference/generate.ts +++ b/src/commands/commandreference/generate.ts @@ -73,6 +73,11 @@ export default class CommandReferenceGenerate extends SfCommand(), + cliMeta + ); events.on('topic', ({ topic }: { topic: string }) => { this.log(chalk.green(`Generating topic '${topic}'`)); diff --git a/src/ditamap/command-helpers.ts b/src/ditamap/command-helpers.ts new file mode 100644 index 00000000..2f0989df --- /dev/null +++ b/src/ditamap/command-helpers.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Dictionary, Optional } from '@salesforce/ts-types'; +import { CommandParameterData, replaceConfigVariables } from '../utils.js'; + +export type FlagInfo = { + hidden: boolean; + description: string; + summary: string; + required: boolean; + kind: string; + type: string; + defaultHelpValue?: string; + default: string | (() => Promise); + aliases?: string[]; + options?: string[]; + char?: string; + deprecated?: { version: string; to: string }; +}; + +export const getDefault = async (flag: FlagInfo, flagName: string): Promise => { + if (!flag) { + return ''; + } + if (flagName === 'target-org' || flagName === 'target-dev-hub') { + return ''; + } + if (typeof flag.default === 'function') { + try { + const help = await flag.default(); + return help.includes('[object Object]') ? '' : help ?? ''; + } catch { + return ''; + } + } else { + return flag.default; + } +}; + +export const flagIsDefined = (input: [string, Optional]): input is [string, FlagInfo] => + input[1] !== undefined; + +export const buildDescription = + (commandName: string) => + (binary: string) => + (flag: FlagInfo): string[] => { + const description = replaceConfigVariables( + Array.isArray(flag?.description) ? flag?.description.join('\n') : flag?.description ?? '', + binary, + commandName + ); + return formatParagraphs( + flag.summary ? `${replaceConfigVariables(flag.summary, binary, commandName)}\n${description}` : description + ); + }; + +export const formatParagraphs = (textToFormat?: string): string[] => + textToFormat ? textToFormat.split('\n').filter((n) => n !== '') : []; + +export const readBinary = (commandMeta: Record): string => + 'binary' in commandMeta && typeof commandMeta.binary === 'string' ? commandMeta.binary : 'unknown'; + +export const buildCommandParameters = async ( + commandName: string, + binary: string, + flags: Dictionary +): Promise => { + const descriptionBuilder = buildDescription(commandName)(binary); + return Promise.all( + [...Object.entries(flags)] + .filter(flagIsDefined) + .filter(([, flag]) => !flag.hidden) + .map( + async ([flagName, flag]) => + ({ + ...flag, + name: flagName, + description: descriptionBuilder(flag), + optional: !flag.required, + kind: flag.kind ?? flag.type, + hasValue: flag.type !== 'boolean', + defaultFlagValue: await getDefault(flag, flagName), + } satisfies CommandParameterData) + ) + ); +}; diff --git a/src/ditamap/command.ts b/src/ditamap/command.ts index a021c518..210c211a 100644 --- a/src/ditamap/command.ts +++ b/src/ditamap/command.ts @@ -15,40 +15,10 @@ */ import { join } from 'node:path'; -import { asString, Dictionary, ensureObject, ensureString, Optional } from '@salesforce/ts-types'; -import { CommandClass, CommandData, CommandParameterData, punctuate, replaceConfigVariables } from '../utils.js'; +import { asString, Dictionary, ensureObject, ensureString } from '@salesforce/ts-types'; +import { CommandClass, CommandData, punctuate, replaceConfigVariables } from '../utils.js'; import { Ditamap } from './ditamap.js'; - -type FlagInfo = { - hidden: boolean; - description: string; - summary: string; - required: boolean; - kind: string; - type: string; - defaultHelpValue?: string; - default: string | (() => Promise); -}; - -const getDefault = async (flag: FlagInfo, flagName: string): Promise => { - if (!flag) { - return ''; - } - if (flagName === 'target-org' || flagName === 'target-dev-hub') { - // special handling to prevent global/local default usernames from appearing in the docs, but they do appear in user's help - return ''; - } - if (typeof flag.default === 'function') { - try { - const help = await flag.default(); - return help.includes('[object Object]') ? '' : help ?? ''; - } catch { - return ''; - } - } else { - return flag.default; - } -}; +import { buildCommandParameters, FlagInfo, readBinary, formatParagraphs } from './command-helpers.js'; export class Command extends Ditamap { private flags: Dictionary; @@ -131,57 +101,14 @@ export class Command extends Ditamap { this.destination = join(Ditamap.outputDir, topic, filename); } - public async getParametersForTemplate(flags: Dictionary): Promise { - const descriptionBuilder = buildDescription(this.commandName)(readBinary(this.commandMeta)); - return Promise.all( - [...Object.entries(flags)] - .filter(flagIsDefined) - .filter(([, flag]) => !flag.hidden) - .map( - async ([flagName, flag]) => - ({ - ...flag, - name: flagName, - description: descriptionBuilder(flag), - optional: !flag.required, - kind: flag.kind ?? flag.type, - hasValue: flag.type !== 'boolean', - defaultFlagValue: await getDefault(flag, flagName), - } satisfies CommandParameterData) - ) - ); - } - // eslint-disable-next-line class-methods-use-this public getTemplateFileName(): string { return 'command.hbs'; } protected async transformToDitamap(): Promise { - const parameters = await this.getParametersForTemplate(this.flags); + const parameters = await buildCommandParameters(this.commandName, readBinary(this.commandMeta), this.flags); this.data = Object.assign({}, this.data, { parameters }); return super.transformToDitamap(); } } - -const flagIsDefined = (input: [string, Optional]): input is [string, FlagInfo] => input[1] !== undefined; - -const buildDescription = - (commandName: string) => - (binary: string) => - (flag: FlagInfo): string[] => { - const description = replaceConfigVariables( - Array.isArray(flag?.description) ? flag?.description.join('\n') : flag?.description ?? '', - binary, - commandName - ); - return formatParagraphs( - flag.summary ? `${replaceConfigVariables(flag.summary, binary, commandName)}\n${description}` : description - ); - }; - -const formatParagraphs = (textToFormat?: string): string[] => - textToFormat ? textToFormat.split('\n').filter((n) => n !== '') : []; - -const readBinary = (commandMeta: Record): string => - 'binary' in commandMeta && typeof commandMeta.binary === 'string' ? commandMeta.binary : 'unknown'; diff --git a/src/docs.ts b/src/docs.ts index ed86b64f..ab713080 100644 --- a/src/docs.ts +++ b/src/docs.ts @@ -17,13 +17,8 @@ import fs from 'node:fs/promises'; import { AnyJson, ensureString } from '@salesforce/ts-types'; import chalk from 'chalk'; -import { BaseDitamap } from './ditamap/base-ditamap.js'; -import { CLIReference } from './ditamap/cli-reference.js'; -import { Command } from './ditamap/command.js'; -import { TopicCommands } from './ditamap/topic-commands.js'; -import { TopicDitamap } from './ditamap/topic-ditamap.js'; import { CliMeta, events, punctuate, SfTopic, SfTopics, CommandClass } from './utils.js'; -import { HelpReference } from './ditamap/help-reference.js'; +import { DitaGeneratorFactory, GeneratorFactory, MarkdownGeneratorFactory, OutputFormat } from './generator-factory.js'; type TopicsByTopicsByTopLevel = Map>; @@ -37,12 +32,17 @@ function emitNoTopicMetadataWarning(topic: string): void { } export class Docs { + private factory: GeneratorFactory; + public constructor( private outputDir: string, + outputFormat: OutputFormat, private hidden: boolean, private topicMeta: SfTopics, private cliMeta: CliMeta - ) {} + ) { + this.factory = outputFormat === 'markdown' ? new MarkdownGeneratorFactory(outputDir) : new DitaGeneratorFactory(); + } public async build(commands: CommandClass[]): Promise { // Create if doesn't exist @@ -77,13 +77,6 @@ export class Docs { for (const [subtopic, classes] of subtopics.entries()) { try { - // const subTopicsMeta = topicMeta.subtopics; - - // if (!subTopicsMeta?.get(subtopic)) { - // emitNoTopicMetadataWarning(`${topic}:${subtopic}`); - // continue; - // } - subTopicNames.push(subtopic); // Commands within the sub topic @@ -110,8 +103,8 @@ export class Docs { // The topic ditamap with all of the subtopic links. events.emit('subtopics', topic, subTopicNames); - await new TopicCommands(topic, topicMeta).write(); - await new TopicDitamap(topic, commandIds).write(); + await this.factory.createTopicCommands(topic, topicMeta).write(); + await this.factory.createTopicIndex(topic, commandIds).write(); return subTopicNames; } @@ -123,7 +116,6 @@ export class Docs { * @returns The commands grouped by topics/subtopic/commands. */ private groupTopicsAndSubtopics(commands: CommandClass[]): TopicsByTopicsByTopLevel { - // const topLevelTopics: Dictionary> = {}; const topLevelTopics = new Map>(); for (const command of commands) { @@ -135,17 +127,14 @@ export class Docs { const plugin = command.plugin; if (plugin) { - // Also include the namespace on the commands so we don't need to do the split at other times in the code. command.topic = topLevelTopic; const existingTopicsForTopLevel = topLevelTopics.get(topLevelTopic) ?? new Map(); if (commandParts.length === 1) { - // This is a top-level topic that is also a command const existingTarget = existingTopicsForTopLevel.get(commandParts[0]) ?? []; existingTopicsForTopLevel.set(commandParts[0], [...existingTarget, command]); } else if (commandParts.length === 2) { - // This is a command directly under the top-level topic const existingTarget = existingTopicsForTopLevel.get(commandParts[1]) ?? []; existingTopicsForTopLevel.set(commandParts[1], [...existingTarget, command]); } else { @@ -177,11 +166,12 @@ export class Docs { private async populateTemplate(commands: CommandClass[]): Promise { const topicsAndSubtopics = this.groupTopicsAndSubtopics(commands); - await new CLIReference().write(); - await new HelpReference().write(); + await this.factory.createCliReference().write(); + + const helpReference = this.factory.createHelpReference(); + if (helpReference) await helpReference.write(); - // Generate one base file with all top-level topics. - await new BaseDitamap(Array.from(topicsAndSubtopics.keys())).write(); + await this.factory.createRootIndex(Array.from(topicsAndSubtopics.keys())).write(); for (const [topic, subtopics] of topicsAndSubtopics.entries()) { events.emit('topic', { topic }); @@ -240,8 +230,8 @@ export class Docs { return ''; } - const commandDitamap = new Command(topic, subtopic, command, commandMeta); - await commandDitamap.write(); - return commandDitamap.getFilename(); + const commandGenerator = this.factory.createCommand(topic, subtopic, command, commandMeta); + await commandGenerator.write(); + return commandGenerator.getFilename(); } } diff --git a/src/generator-factory.ts b/src/generator-factory.ts new file mode 100644 index 00000000..d12e1f79 --- /dev/null +++ b/src/generator-factory.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseDitamap } from './ditamap/base-ditamap.js'; +import { CLIReference } from './ditamap/cli-reference.js'; +import { Command as DitaCommand } from './ditamap/command.js'; +import { Ditamap } from './ditamap/ditamap.js'; +import { HelpReference } from './ditamap/help-reference.js'; +import { TopicCommands } from './ditamap/topic-commands.js'; +import { TopicDitamap } from './ditamap/topic-ditamap.js'; +import { MarkdownCliReference } from './markdown/cli-reference.js'; +import { MarkdownCommand } from './markdown/command.js'; +import { MarkdownRootIndex } from './markdown/root-index.js'; +import { MarkdownTopicCommands } from './markdown/topic-commands.js'; +import { MarkdownTopicIndex } from './markdown/topic-index.js'; +import { CommandClass, SfTopic } from './utils.js'; + +export type OutputFormat = 'dita' | 'markdown'; + +type Writable = { write(): Promise }; +type WritableWithFilename = Writable & { getFilename(): string }; + +export type GeneratorFactory = { + createCliReference(): Writable; + createHelpReference(): Writable | null; + createRootIndex(topics: string[]): Writable; + createTopicCommands(topic: string, topicMeta: SfTopic): Writable; + createTopicIndex(topic: string, commandIds: string[]): Writable; + createCommand( + topic: string, + subtopic: string | null, + command: CommandClass, + commandMeta: Record + ): WritableWithFilename; +}; + +export class DitaGeneratorFactory implements GeneratorFactory { + // eslint-disable-next-line class-methods-use-this + public createCliReference(): Writable { + return new CLIReference(); + } + + // eslint-disable-next-line class-methods-use-this + public createHelpReference(): Writable { + return new HelpReference(); + } + + // eslint-disable-next-line class-methods-use-this + public createRootIndex(topics: string[]): Writable { + return new BaseDitamap(topics); + } + + // eslint-disable-next-line class-methods-use-this + public createTopicCommands(topic: string, topicMeta: SfTopic): Writable { + return new TopicCommands(topic, topicMeta); + } + + // eslint-disable-next-line class-methods-use-this + public createTopicIndex(topic: string, commandIds: string[]): Writable { + return new TopicDitamap(topic, commandIds); + } + + // eslint-disable-next-line class-methods-use-this + public createCommand( + topic: string, + subtopic: string | null, + command: CommandClass, + commandMeta: Record + ): WritableWithFilename { + return new DitaCommand(topic, subtopic, command, commandMeta); + } +} + +export class MarkdownGeneratorFactory implements GeneratorFactory { + public constructor(private outputDir: string) {} + + public createCliReference(): Writable { + return new MarkdownCliReference(Ditamap.cliVersion, Ditamap.pluginVersions, this.outputDir); + } + + // eslint-disable-next-line class-methods-use-this + public createHelpReference(): null { + return null; + } + + public createRootIndex(topics: string[]): Writable { + return new MarkdownRootIndex(topics, this.outputDir); + } + + public createTopicCommands(topic: string, topicMeta: SfTopic): Writable { + return new MarkdownTopicCommands(topic, topicMeta, this.outputDir); + } + + public createTopicIndex(topic: string, commandIds: string[]): Writable { + return new MarkdownTopicIndex(topic, commandIds, this.outputDir); + } + + public createCommand( + topic: string, + subtopic: string | null, + command: CommandClass, + commandMeta: Record + ): WritableWithFilename { + return new MarkdownCommand(topic, subtopic, command, commandMeta, this.outputDir); + } +} diff --git a/src/markdown/cli-reference.ts b/src/markdown/cli-reference.ts new file mode 100644 index 00000000..6ec97bea --- /dev/null +++ b/src/markdown/cli-reference.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MarkdownBase } from './markdown-base.js'; + +export class MarkdownCliReference extends MarkdownBase { + public constructor( + private cliVersion: string, + private pluginVersions: Array<{ name: string; version: string }>, + outputDir: string + ) { + super(MarkdownBase.file('cli_reference'), outputDir); + } + + protected generate(): Promise { + const lines: string[] = []; + lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push(''); + lines.push('# sf CLI Command Reference'); + lines.push(''); + lines.push('An alphabetized list of sf CLI commands and their descriptions, arguments, and flags.'); + lines.push(''); + lines.push(`CLI version: \`${this.cliVersion}\``); + lines.push(''); + if (this.pluginVersions.length > 0) { + lines.push('## Plugin Versions'); + lines.push(''); + lines.push('| Plugin | Version |'); + lines.push('|--------|---------|'); + for (const { name, version } of this.pluginVersions) { + lines.push(`| \`${name}\` | \`${version}\` |`); + } + lines.push(''); + } + return Promise.resolve(lines.join('\n')); + } +} diff --git a/src/markdown/command.ts b/src/markdown/command.ts new file mode 100644 index 00000000..e8e50a61 --- /dev/null +++ b/src/markdown/command.ts @@ -0,0 +1,183 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { join } from 'node:path'; +import { asString, Dictionary, ensureObject, ensureString } from '@salesforce/ts-types'; +import { CommandClass, CommandParameterData, punctuate, replaceConfigVariables } from '../utils.js'; +import { buildCommandParameters, FlagInfo, formatParagraphs, readBinary } from '../ditamap/command-helpers.js'; +import { MarkdownBase } from './markdown-base.js'; + +type ParsedExample = { + description: string; + commands: string[]; +}; + +export class MarkdownCommand extends MarkdownBase { + private flags: Dictionary; + private commandMeta: Record; + private commandName: string; + private summary: string | undefined; + private help: string[]; + private examples: ParsedExample[]; + private state: unknown; + private deprecated: boolean; + + public constructor( + topic: string, + subtopic: string | null, + command: CommandClass, + commandMeta: Record = {}, + outputDir: string + ) { + const commandWithUnderscores = ensureString(command.id).replace(/:/g, '_'); + const filename = MarkdownBase.file(`cli_reference_${commandWithUnderscores}`); + super(filename, outputDir); + this.destination = join(outputDir, topic, filename); + + this.flags = ensureObject(command.flags); + this.commandMeta = commandMeta; + const binary = readBinary(this.commandMeta); + + this.summary = punctuate(command.summary); + this.commandName = `${binary} ${command.id.replace(/:/g, asString(this.commandMeta.topicSeparator, ' '))}`; + + const description = command.description + ? replaceConfigVariables(command.description, binary, this.commandName) + : undefined; + + this.help = formatParagraphs(description); + + this.examples = (command.examples ?? []).map((example) => { + let desc: string | null; + let commands: string[]; + if (typeof example === 'string') { + const parts = example.split('\n'); + desc = parts.length > 1 ? parts[0] : null; + commands = parts.length > 1 ? parts.slice(1) : [parts[0]]; + } else { + desc = example.description; + commands = [example.command]; + } + return { + description: replaceConfigVariables(desc ?? '', binary, this.commandName), + commands: commands.map((cmd) => replaceConfigVariables(cmd, binary, this.commandName)), + }; + }); + + this.state = command.state ?? this.commandMeta.state; + this.deprecated = (command.deprecated as boolean) ?? this.state === 'deprecated' ?? false; + } + + protected async generate(): Promise { + const binary = readBinary(this.commandMeta); + const parameters = await buildCommandParameters(this.commandName, binary, this.flags); + + const lines: string[] = []; + + lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push(''); + lines.push(`# ${this.commandName}`); + lines.push(''); + + if (this.summary) { + lines.push(this.summary); + lines.push(''); + } + + if (this.deprecated) { + lines.push('> **Deprecated**'); + lines.push(''); + } else if (this.state === 'beta') { + lines.push('> **Beta**'); + lines.push(''); + } else if (this.state === 'preview') { + lines.push('> **Preview**'); + lines.push(''); + } else if (this.state === 'closedPilot') { + lines.push('> **Closed Pilot**'); + lines.push(''); + } else if (this.state === 'openPilot') { + lines.push('> **Open Pilot**'); + lines.push(''); + } + + if (this.help.length > 0) { + lines.push('## Description'); + lines.push(''); + for (const paragraph of this.help) { + lines.push(paragraph); + lines.push(''); + } + } + + if (parameters.length > 0) { + lines.push('## Flags'); + lines.push(''); + lines.push('| Flag | Description |'); + lines.push('|------|-------------|'); + for (const param of parameters) { + lines.push(renderFlagRow(param)); + } + lines.push(''); + } + + if (this.examples.length > 0) { + lines.push('## Examples'); + lines.push(''); + for (const example of this.examples) { + if (example.description) { + lines.push(example.description); + lines.push(''); + } + for (const cmd of example.commands) { + lines.push('```shell'); + lines.push(cmd.trim()); + lines.push('```'); + lines.push(''); + } + } + } + + return lines.join('\n'); + } +} + +function renderFlagRow(param: CommandParameterData): string { + const flagLabel = renderFlagLabel(param); + const desc = renderFlagDescription(param); + return `| ${flagLabel} | ${desc} |`; +} + +function renderFlagLabel(param: CommandParameterData): string { + const parts: string[] = []; + if (param.char) parts.push(`\`-${param.char}\``); + const longFlag = param.hasValue ? `\`--${param.name} ${param.name.toUpperCase()}\`` : `\`--${param.name}\``; + parts.push(longFlag); + return parts.join(', '); +} + +function renderFlagDescription(param: CommandParameterData): string { + const parts: string[] = []; + if (!param.optional) parts.push('**Required.**'); + const desc = param.description.join(' ').replace(/\|/g, '|'); + if (desc) parts.push(desc); + if (param.defaultFlagValue) parts.push(`Default: \`${param.defaultFlagValue}\`.`); + if (param.options?.length) parts.push(`Options: ${param.options.map((o) => `\`${o}\``).join(', ')}.`); + if (param.deprecated) { + parts.push(`Deprecated${param.deprecated.to ? `, use \`--${param.deprecated.to}\`` : ''}.`); + } + return parts.join(' ').replace(/\n/g, ' '); +} diff --git a/src/markdown/index.ts b/src/markdown/index.ts new file mode 100644 index 00000000..d37f1a8c --- /dev/null +++ b/src/markdown/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { MarkdownBase } from './markdown-base.js'; +export { MarkdownCommand } from './command.js'; +export { MarkdownCliReference } from './cli-reference.js'; +export { MarkdownRootIndex } from './root-index.js'; +export { MarkdownTopicCommands } from './topic-commands.js'; +export { MarkdownTopicIndex } from './topic-index.js'; diff --git a/src/markdown/markdown-base.ts b/src/markdown/markdown-base.ts new file mode 100644 index 00000000..b67f6c6a --- /dev/null +++ b/src/markdown/markdown-base.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { dirname, join } from 'node:path'; +import fs from 'node:fs/promises'; + +export abstract class MarkdownBase { + protected destination: string; + + protected constructor(private filename: string, protected outputDir: string) { + this.destination = join(outputDir, filename); + } + + public static file(name: string): string { + return `${name}.md`; + } + + public getFilename(): string { + return this.filename; + } + + public async write(): Promise { + await fs.mkdir(dirname(this.destination), { recursive: true }); + const output = await this.generate(); + await fs.writeFile(this.destination, output); + } + + protected abstract generate(): Promise; +} diff --git a/src/markdown/root-index.ts b/src/markdown/root-index.ts new file mode 100644 index 00000000..946b16b9 --- /dev/null +++ b/src/markdown/root-index.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MarkdownBase } from './markdown-base.js'; + +export class MarkdownRootIndex extends MarkdownBase { + public constructor(private topics: string[], outputDir: string) { + super(MarkdownBase.file('cli_reference_index'), outputDir); + } + + protected generate(): Promise { + const lines: string[] = []; + lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push(''); + lines.push('# sf CLI Reference — Topic Index'); + lines.push(''); + for (const topic of this.topics.sort()) { + lines.push(`- [${topic}](./${topic}/cli_reference_${topic}.md)`); + } + lines.push(''); + return Promise.resolve(lines.join('\n')); + } +} diff --git a/src/markdown/topic-commands.ts b/src/markdown/topic-commands.ts new file mode 100644 index 00000000..42859d10 --- /dev/null +++ b/src/markdown/topic-commands.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { join } from 'node:path'; +import { SfTopic } from '../utils.js'; +import { MarkdownBase } from './markdown-base.js'; + +export class MarkdownTopicCommands extends MarkdownBase { + public constructor(private topic: string, private topicMeta: SfTopic, outputDir: string) { + const filename = MarkdownBase.file(`cli_reference_${topic}_commands`); + super(filename, outputDir); + this.destination = join(outputDir, topic, filename); + } + + protected generate(): Promise { + const lines: string[] = []; + lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push(''); + lines.push(`# ${this.topic} Commands`); + lines.push(''); + if (this.topicMeta.description) { + lines.push(this.topicMeta.description); + lines.push(''); + } + return Promise.resolve(lines.join('\n')); + } +} diff --git a/src/markdown/topic-index.ts b/src/markdown/topic-index.ts new file mode 100644 index 00000000..0a29be9c --- /dev/null +++ b/src/markdown/topic-index.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { join } from 'node:path'; +import { MarkdownBase } from './markdown-base.js'; + +export class MarkdownTopicIndex extends MarkdownBase { + public constructor(private topic: string, private commandIds: string[], outputDir: string) { + const filename = MarkdownBase.file(`cli_reference_${topic}`); + super(filename, outputDir); + this.destination = join(outputDir, topic, filename); + } + + protected generate(): Promise { + const lines: string[] = []; + lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push(''); + lines.push(`# ${this.topic} Commands`); + lines.push(''); + for (const id of [...this.commandIds].sort()) { + const commandWithUnderscores = id.replace(/:/g, '_'); + const commandWithSpaces = id.replace(/:/g, ' '); + lines.push(`- [${commandWithSpaces}](./cli_reference_${commandWithUnderscores}.md)`); + } + lines.push(''); + return Promise.resolve(lines.join('\n')); + } +} diff --git a/test/tmp-md/cli_reference.md b/test/tmp-md/cli_reference.md new file mode 100644 index 00000000..9aa3990b --- /dev/null +++ b/test/tmp-md/cli_reference.md @@ -0,0 +1,14 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf CLI Command Reference + +An alphabetized list of sf CLI commands and their descriptions, arguments, and flags. + +CLI version: `3.1.95` + +## Plugin Versions + +| Plugin | Version | +| ------------------------- | -------- | +| `@salesforce/plugin-auth` | `3.9.26` | +| `@salesforce/plugin-user` | `3.6.44` | diff --git a/test/tmp-md/cli_reference_index.md b/test/tmp-md/cli_reference_index.md new file mode 100644 index 00000000..685c62db --- /dev/null +++ b/test/tmp-md/cli_reference_index.md @@ -0,0 +1,5 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf CLI Reference — Topic Index + +- [org](./org/cli_reference_org.md) diff --git a/test/tmp-md/org/cli_reference_org.md b/test/tmp-md/org/cli_reference_org.md new file mode 100644 index 00000000..2a50712e --- /dev/null +++ b/test/tmp-md/org/cli_reference_org.md @@ -0,0 +1,16 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# org Commands + +- [org assign permset](./cli_reference_org_assign_permset.md) +- [org assign permsetlicense](./cli_reference_org_assign_permsetlicense.md) +- [org create user](./cli_reference_org_create_user.md) +- [org display user](./cli_reference_org_display_user.md) +- [org generate password](./cli_reference_org_generate_password.md) +- [org list auth](./cli_reference_org_list_auth.md) +- [org list users](./cli_reference_org_list_users.md) +- [org login access-token](./cli_reference_org_login_access-token.md) +- [org login jwt](./cli_reference_org_login_jwt.md) +- [org login sfdx-url](./cli_reference_org_login_sfdx-url.md) +- [org login web](./cli_reference_org_login_web.md) +- [org logout](./cli_reference_org_logout.md) diff --git a/test/tmp-md/org/cli_reference_org_assign_permset.md b/test/tmp-md/org/cli_reference_org_assign_permset.md new file mode 100644 index 00000000..ef4a44ce --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_assign_permset.md @@ -0,0 +1,42 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org assign permset + +Assign a permission set to one or more org users. + +## Description + +To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. + +To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-n`, `--name NAME` | **Required.** Permission set to assign. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Username or alias to assign the permission set to. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +Assign two permission sets called DreamHouse and CloudHouse to original admin user of your default org: + +```shell +sf sf org assign permset --name DreamHouse --name CloudHouse +``` + +Assign the Dreamhouse permission set to the original admin user of the org with alias "my-scratch": + +```shell +sf sf org assign permset --name DreamHouse --target-org my-scratch +``` + +Assign the Dreamhouse permission set to the specified list of users of your default org: + +```shell +sf sf org assign permset --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user +``` diff --git a/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md b/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md new file mode 100644 index 00000000..99face1e --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md @@ -0,0 +1,42 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org assign permsetlicense + +Assign a permission set license to one or more org users. + +## Description + +To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. + +To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-n`, `--name NAME` | **Required.** Name of the permission set license to assign. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Usernames or alias to assign the permission set license to. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +Assign the DreamHouse permission set license to original admin user of your default org: + +```shell +sf sf org assign permsetlicense --name DreamHouse +``` + +Assign two permission set licenses to the original admin user of the org with alias "my-scratch": + +```shell +sf sf org assign permsetlicense --name DreamHouse --name CloudHouse --target-org my-scratch +``` + +Assign the Dreamhouse permission set license to the specified list of users of your default org: + +```shell +sf sf org assign permsetlicense --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user3 +``` diff --git a/test/tmp-md/org/cli_reference_org_commands.md b/test/tmp-md/org/cli_reference_org_commands.md new file mode 100644 index 00000000..88a3df7c --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_commands.md @@ -0,0 +1,3 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# org Commands diff --git a/test/tmp-md/org/cli_reference_org_create_user.md b/test/tmp-md/org/cli_reference_org_create_user.md new file mode 100644 index 00000000..edf1e130 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_create_user.md @@ -0,0 +1,67 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org create user + +Create a user for a scratch org. + +## Description + +A scratch org includes one administrator user by default. For testing purposes, however, you sometimes need to create additional users. + +The easiest way to create a user is to let this command assign default or generated characteristics to the new user. If you want to customize your new user, create a definition file and specify it with the --definition-file flag. In the file, you can include all the User sObject (SSalesforce object) fields and Salesforce DX-specific options, as described in "User Definition File for Customizing a Scratch Org User" (https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm). You can also specify these options on the command line. + +If you don't customize your new user, this command creates a user with the following default characteristics: + + * The username is the existing administrator’s username prepended with a timestamp, such as 1505759162830_test-wvkpnfm5z113@example.com. + + * The user’s profile is Standard User. + + * The values of the required fields of the User sObject are the corresponding values of the administrator user. + + * The user has no password. + +Use the --set-alias flag to assign a simple name to the user that you can reference in later CLI commands. This alias is local and different from the Alias field of the User sObject record of the new user, which you set in the Setup UI. + +When this command completes, it displays the new username and user ID. Run the "org display user" command to get more information about the new user. + +After the new user has been created, Salesforce CLI automatically authenticates it to the scratch org so the new user can immediately start using the scratch org. The CLI uses the same authentication method that was used on the associated Dev Hub org. Due to Hyperforce limitations, the scratch org user creation fails if the Dev Hub authentication used the JWT flow and the scratch org is on Hyperforce. For this reason, if you plan to create scratch org users, authenticate to the Dev Hub org with either the "org login web" or "org login sfdx-url" command, and not "org login jwt". + +For more information about user limits, defaults, and other considerations when creating a new scratch org user, see https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users.htm. + +## Flags + +| Flag | Description | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-a`, `--set-alias SET-ALIAS` | Set an alias for the created username to reference in other CLI commands. | +| `-f`, `--definition-file DEFINITION-FILE` | File path to a user definition file for customizing the new user. The user definition file uses JSON format and can include any Salesforce User sObject field and Salesforce DX-specific options. See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm for more information. | +| `-s`, `--set-unique-username` | Force the username, if specified in the definition file or at the command line, to be unique by appending the org ID. The new user’s username must be unique across all Salesforce orgs and in the form of an email address. If you let this command generate a username for you, it's guaranteed to be unique. If you specify an existing username in a definition file, the command fails. Set this flag to force the username to be unique; as a result, the username might be different than what you specify in the definition file. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +Create a user for your default scratch org and let this command generate a username, user ID, and other characteristics: + +```shell +sf sf org create user +``` + +Create a user with alias "testuser1" using a user definition file. Set the "profileName" option to "Chatter Free User", which overrides the value in the defintion file if it also exists there. Create the user for the scratch org with alias "my-scratch": + +```shell +sf sf org create user --set-alias testuser1 --definition-file config/project-user-def.json profileName='Chatter Free User' --target-org my-scratch +``` + +Create a user by specifying the username, email, and perm set assignment at the command line; command fails if the username already exists in Salesforce: + +```shell +sf sf org create user username=testuser1@my.org email=me@my.org permsets=DreamHouse +``` + +Create a user with a definition file, set the email value as specified (overriding any value in the definition file), and generate a password for the user. If the username in the definition file isn't unique, the command appends the org ID to make it unique: + +```shell +sf sf org create user --definition-file config/project-user-def.json email=me@my.org generatepassword=true --set-unique-username +``` diff --git a/test/tmp-md/org/cli_reference_org_display_user.md b/test/tmp-md/org/cli_reference_org_display_user.md new file mode 100644 index 00000000..258d683b --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_display_user.md @@ -0,0 +1,32 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org display user + +Display information about a Salesforce user. + +## Description + +Output includes the profile name, org ID, access token, instance URL, login URL, and alias if applicable. The displayed alias is local and different from the Alias field of the User sObject record of the new user, which you set in the Setup UI. + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +Display information about the admin user of your default scratch org: + +```shell +sf sf org display user +``` + +Display information about the specified user and output in JSON format: + +```shell +sf sf org display user --target-org me@my.org --json +``` diff --git a/test/tmp-md/org/cli_reference_org_generate_password.md b/test/tmp-md/org/cli_reference_org_generate_password.md new file mode 100644 index 00000000..71059e49 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_generate_password.md @@ -0,0 +1,65 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org generate password + +Generate a random password for scratch org users. + +## Description + +By default, new scratch orgs contain one admin user with no password. Use this command to generate or change a password for this admin user. After it's set, you can’t unset a password, you can only change it. + +You can also use the --on-behalf-of flag to generate a password for a scratch org user that you've created locally with the "org create user" command. This command doesn't work for users you created in the scratch org using Setup. + +To change the password strength, set the --complexity flag to a value between 0 and 5. Each value specifies the types of characters used in the generated password: + +0 - lower case letters only + +1 - lower case letters and numbers only + +2 - lower case letters and symbols only + +3 - lower and upper case letters and numbers only + +4 - lower and upper case letters and symbols only + +5 - lower and upper case letters and numbers and symbols only + +To see a password that was previously generated, run "org display user". + +## Flags + +| Flag | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Comma-separated list of usernames or aliases to assign the password to; must have been created locally with the "org create user" command. | +| `-l`, `--length LENGTH` | Number of characters in the generated password; valid values are between 8 and 100. Default: `13`. | +| `-c`, `--complexity COMPLEXITY` | Level of password complexity or strength; the higher the value, the stronger the password. Default: `5`. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +Generate a password for the original admin user of your default scratch org: + +```shell +sf sf org generate password +``` + +Generate a password that contains 12 characters for the original admin user of the scratch org with alias "my-scratch": + +```shell +sf sf org generate password --length 12 --target-org my-scratch +``` + +Generate a password for your default scratch org admin user that uses lower and upper case letters and numbers only: + +```shell +sf sf org generate password --complexity 3 +``` + +Generate a password for the specified users in the default scratch org; these users must have been created locally with the "org create user" command: + +```shell +sf sf org generate password --on-behalf-of user1@my.org --on-behalf-of user2@my.org --on-behalf-of user3@my.org +``` diff --git a/test/tmp-md/org/cli_reference_org_list_auth.md b/test/tmp-md/org/cli_reference_org_list_auth.md new file mode 100644 index 00000000..3604f565 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_list_auth.md @@ -0,0 +1,24 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org list auth + +List authorization information about the orgs you created or logged into. + +## Description + +This command uses local authorization information that Salesforce CLI caches when you create a scratch org or log into an org. The command doesn't actually connect to the orgs to verify that they're still active. As a result, this command executes very quickly. If you want to view live information about your authorized orgs, such as their connection status, use the "org list" command. + +## Flags + +| Flag | Description | +| ----------------------- | ------------------------------------ | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | + +## Examples + +List local authorization information about your orgs: + +```shell +sf sf org list auth +``` diff --git a/test/tmp-md/org/cli_reference_org_list_users.md b/test/tmp-md/org/cli_reference_org_list_users.md new file mode 100644 index 00000000..6ee31575 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_list_users.md @@ -0,0 +1,32 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org list users + +List all locally-authenticated users of an org. + +## Description + +For scratch orgs, the list includes any users you've created with the "org create user" command; the original scratch org admin user is marked with "(A)". For other orgs, the list includes the users you used to authenticate to the org. + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | + +## Examples + +List the locally-authenticated users of your default org: + +```shell +sf sf org list users +``` + +List the locally-authenticated users of the specified org: + +```shell +sf sf org list users --target-org me@my.org +``` diff --git a/test/tmp-md/org/cli_reference_org_login_access-token.md b/test/tmp-md/org/cli_reference_org_login_access-token.md new file mode 100644 index 00000000..9691c97c --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_login_access-token.md @@ -0,0 +1,37 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org login access-token + +Authorize an org using an existing Salesforce access token. + +## Description + +By default, the command runs interactively and asks you for the access token. If you previously authorized the org, the command prompts whether you want to overwrite the local file. Specify --no-prompt to not be prompted. + +To use the command in a CI/CD script, set the SF_ACCESS_TOKEN environment variable to the access token. Then run the command with the --no-prompt parameter. + +## Flags + +| Flag | Description | +| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-r`, `--instance-url INSTANCE-URL` | **Required.** URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | +| `-p`, `--no-prompt` | Don't prompt for confirmation. | + +## Examples + +Authorize an org on https://mycompany.my.salesforce.com; the command prompts you for the access token: + +```shell +sf sf org login access-token --instance-url https://mycompany.my.salesforce.com +``` + +Authorize the org without being prompted; you must have previously set the SF_ACCESS_TOKEN environment variable to the access token: + +```shell +sf sf org login access-token --instance-url https://dev-hub.my.salesforce.com --no-prompt +``` diff --git a/test/tmp-md/org/cli_reference_org_login_jwt.md b/test/tmp-md/org/cli_reference_org_login_jwt.md new file mode 100644 index 00000000..bcfcb9bc --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_login_jwt.md @@ -0,0 +1,63 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org login jwt + +Log in to a Salesforce org using a JSON web token (JWT). + +## Description + +Use this command in automated environments where you can’t interactively log in with a browser, such as in CI/CD scripts. + +Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving a project. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. + +Complete these steps before you run this command: + + 1. Create a digital certificate (also called digital signature) and the private key to sign the certificate. You can use your own key and certificate issued by a certification authority. Or use OpenSSL to create a key and a self-signed digital certificate. + + 2. Store the private key in a file on your computer. When you run this command, you set the --jwt-key-file flag to this file. + + 3. Create a custom connected app in your org using the digital certificate. Make note of the consumer key (also called client id) that’s generated for you. Be sure the username of the user logging in is approved to use the connected app. When you run this command, you set the --client-id flag to the consumer key. + +See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_jwt_flow.htm for more information. + +We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. Use --set-default for your default scratch org or sandbox, or --set-default-dev-hub for your default Dev Hub. + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--username USERNAME` | **Required.** Username of the user logging in. | +| `-f`, `--jwt-key-file JWT-KEY-FILE` | **Required.** Path to a file containing the private key. | +| `-i`, `--client-id CLIENT-ID` | **Required.** OAuth client ID (also called consumer key) of your custom connected app. | +| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | + +## Examples + +Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.com). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. + +```shell +sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 +``` + +Set the org as the default and give it an alias: + +```shell +sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default +``` + +Set the org as the default Dev Hub and give it an alias: + +```shell +sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-dev-hub --set-default-dev-hub +``` + +Log in to a sandbox using URL https://MyDomainName--SandboxName.sandbox.my.salesforce.com: + +```shell +sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com +``` diff --git a/test/tmp-md/org/cli_reference_org_login_sfdx-url.md b/test/tmp-md/org/cli_reference_org_login_sfdx-url.md new file mode 100644 index 00000000..3d17348d --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_login_sfdx-url.md @@ -0,0 +1,57 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org login sfdx-url + +Authorize an org using a Salesforce DX authorization URL stored in a file or through standard input (stdin). + +## Description + +You use the Salesforce DX (SFDX) authorization URL to authorize Salesforce CLI to connect to a target org. The URL contains the required data to accomplish the authorization, such as the client ID, client secret, and instance URL. You must specify the SFDX authorization URL in this format: "force://::@". Replace , , , and with the values specific to your target org. For , don't include a protocol (such as "https://"). Note that although the SFDX authorization URL starts with "force://", it has nothing to do with the actual authorization. Salesforce CLI always communicates with your org using HTTPS. + +To see an example of an SFDX authorization URL, run "org display --verbose" on an org. + +You have three options when creating the authorization file. The easiest option is to redirect the output of the "sf org display --verbose --json" command into a file. For example, using an org with alias my-org that you've already authorized: + + $ sf org display --target-org my-org --verbose --json > authFile.json + +The resulting JSON file contains the URL in the "sfdxAuthUrl" property of the "result" object. You can then reference the file when running this command: + + $ sf sf org login sfdx-url --sfdx-url-file authFile.json + +NOTE: The "sf org display --verbose" command displays the refresh token only for orgs authorized with the web server flow, and not the JWT bearer flow. + +You can also create a JSON file that has a top-level property named sfdxAuthUrl whose value is the authorization URL. Finally, you can create a normal text file that includes just the URL and nothing else. + +Alternatively, you can pipe the SFDX authorization URL through standard input by specifying the --sfdx-url-stdin flag. + +## Flags + +| Flag | Description | +| --------------------------------------- | ----------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-f`, `--sfdx-url-file SFDX-URL-FILE` | Path to a file that contains the Salesforce DX authorization URL. | +| `-u`, `--sfdx-url-stdin SFDX-URL-STDIN` | Pipe the Salesforce DX authorization URL through standard input (stdin). | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | + +## Examples + +Authorize an org using the SFDX authorization URL in the files/authFile.json file: + +```shell +sf sf org login sfdx-url --sfdx-url-file files/authFile.json +``` + +Similar to previous example, but set the org as your default and give it an alias MyDefaultOrg: + +```shell +sf sf org login sfdx-url --sfdx-url-file files/authFile.json --set-default --alias MyDefaultOrg +``` + +Pipe the SFDX authorization URL from stdin: + +```shell +$ echo url | sf sf org login sfdx-url --sfdx-url-stdin +``` diff --git a/test/tmp-md/org/cli_reference_org_login_web.md b/test/tmp-md/org/cli_reference_org_login_web.md new file mode 100644 index 00000000..dd09d3e7 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_login_web.md @@ -0,0 +1,65 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org login web + +Log in to a Salesforce org using the web server flow. + +## Description + +Opens a Salesforce instance URL in a web browser so you can enter your credentials and log in to your org. After you log in, you can close the browser window. + +Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving metadata. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. + +We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. Use --set-default for your default scratch org or sandbox, or --set-default-dev-hub for your default Dev Hub. + +By default, this command uses the global out-of-the-box connected app in your org. If you need more security or control, such as setting the refresh token timeout or specifying IP ranges, create your own connected app using a digital certificate. Make note of the consumer key (also called cliend id) that’s generated for you. Then specify the consumer key with the --client-id flag. + +You can also use this command to link one or more connected or external client apps in an org to an already-authenticated user. Then Salesforce CLI commands that have API-specific requirements, such as new OAuth scopes or JWT-based access tokens, can use these custom client apps rather than the default one. To create the link, you use the --client-app flag to give the link a name and the --username flag to specify the already-authenticated user. Use the --scopes flag to add OAuth scopes if required. After you create the link, you then use the --client-app value in the other command that has the API-specific requirements. An example of a command that uses this feature is "agent preview"; see the "Preview an Agent" section in the "Agentforce Developer Guide" for details and examples. (https://developer.salesforce.com/docs/einstein/genai/guide/agent-dx-preview.html) + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-b`, `--browser BROWSER` | Browser in which to open the org. If you don’t specify --browser, the command uses your default browser. The exact names of the browser applications differ depending on the operating system you're on; check your documentation for details. Options: `chrome`, `edge`, `firefox`. | +| `-i`, `--client-id CLIENT-ID` | OAuth client ID (also called consumer key) of your custom connected app. | +| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | +| `-c`, `--client-app CLIENT-APP` | Name to give to the link between the connected app or external client and the already-authenticated user. You can specify any string you want. Must be used with --username. | +| `--username USERNAME` | Username of the already-authenticated user to link to the connected app or external client app. Must be used with --client-app. | +| `--scopes SCOPES` | Authentication (OAuth) scopes to request. Use the scope's short name; specify multiple scopes using just one flag instance and separated by spaces: --scopes "sfap_api chatbot_api". | + +## Examples + +Run the command with no flags to open the default Salesforce login page (https://login.salesforce.com): + +```shell +sf sf org login web +``` + +Log in to your Dev Hub, set it as your default Dev Hub, and set an alias that you reference later when you create a scratch org: + +```shell +sf sf org login web --set-default-dev-hub --alias dev-hub +``` + +Log in to a sandbox and set it as your default org: + +```shell +sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default +``` + +Use --browser to specify a specific browser, such as Google Chrome: + +```shell +sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome +``` + +Use your own connected app by specifying its consumer key (also called client ID) and specify additional OAuth scopes: + +```shell +sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome --client-id 04580y4051234051 --scopes "sfap_api chatbot_api" +``` diff --git a/test/tmp-md/org/cli_reference_org_logout.md b/test/tmp-md/org/cli_reference_org_logout.md new file mode 100644 index 00000000..a8441714 --- /dev/null +++ b/test/tmp-md/org/cli_reference_org_logout.md @@ -0,0 +1,52 @@ +> **Note:** This file is autogenerated. Do not edit manually. + +# sf org logout + +Log out of a Salesforce org. + +## Description + +If you run this command with no flags and no default org set in your config or environment, it first displays a list of orgs you've created or logged into, with none of the orgs selected. Use the arrow keys to scroll through the list and the space bar to select the orgs you want to log out of. Press Enter when you're done; the command asks for a final confirmation before logging out of the selected orgs. + +The process is similar if you specify --all, except that in the initial list of orgs, they're all selected. Use --target-org to logout of a specific org. In both these cases by default, you must still confirm that you want to log out. Use --no-prompt to never be asked for confirmation when also using --all or --target-org. + +Be careful! If you log out of a scratch org without having access to its password, you can't access the scratch org again, either through the CLI or the Salesforce UI. + +Use the --client-app flag to log out of the link you previously created between an authenticated user and a connected app or external client app; you create these links with "org login web --client-app". Run "org display" to get the list of client app names. + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | Username or alias of the target org. | +| `-c`, `--client-app CLIENT-APP` | Client app to log out of. | +| `-a`, `--all` | Include all authenticated orgs. All orgs includes Dev Hubs, sandboxes, DE orgs, and expired, deleted, and unknown-status scratch orgs. | +| `-p`, `--no-prompt` | Don't prompt for confirmation. | + +## Examples + +Interactively select the orgs to log out of: + +```shell +sf sf org logout +``` + +Log out of the org with username me@my.org: + +```shell +sf sf org logout --target-org me@my.org +``` + +Log out of all orgs after confirmation: + +```shell +sf sf org logout --all +``` + +Logout of the org with alias my-scratch and don't prompt for confirmation: + +```shell +sf sf org logout --target-org my-scratch --no-prompt +``` diff --git a/test/unit/markdown.test.ts b/test/unit/markdown.test.ts new file mode 100644 index 00000000..b6e708cd --- /dev/null +++ b/test/unit/markdown.test.ts @@ -0,0 +1,113 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { access, rm } from 'node:fs/promises'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { expect } from 'chai'; + +const testFilesPath = './test/tmp-md'; + +function loadMdFile(path: string): string { + return readFileSync(join(testFilesPath, path), 'utf8'); +} + +describe('markdown output: plugin-auth and user', () => { + before(async () => { + try { + await access(testFilesPath); + } catch (e) { + throw new Error( + `Could not read generated Markdown test docs from ${testFilesPath}. Ensure the "test:command-reference-markdown" wireit task has run.` + ); + } + }); + + after(async () => { + await rm(testFilesPath, { recursive: true }); + }); + + it('produces no [object Object] nonsense for default flags', () => { + const md = loadMdFile(join('org', 'cli_reference_org_create_user.md')); + expect(md.includes('[object Object]')).to.be.false; + }); + + it('creates a command file with the correct H1 heading', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md.includes('# sf org login jwt')).to.be.true; + }); + + it('includes the command summary', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md.includes('Log in to a Salesforce org using a JSON web token (JWT).')).to.be.true; + }); + + it('includes a Flags section with a Markdown table', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md.includes('## Flags')).to.be.true; + expect(md.includes('| Flag | Description |')).to.be.true; + expect(md.includes('--username')).to.be.true; + }); + + it('includes an Examples section with a shell code block', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md.includes('## Examples')).to.be.true; + expect(md.includes('```shell')).to.be.true; + }); + + it('does not contain XML or DITA markup', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md.includes(' { + const md = loadMdFile(join('org', 'cli_reference_org.md')); + expect(md.includes('# org Commands')).to.be.true; + expect(md.includes('cli_reference_org_login_jwt.md')).to.be.true; + }); + + it('creates a topic commands overview file', () => { + const md = loadMdFile(join('org', 'cli_reference_org_commands.md')); + expect(md.includes('# org Commands')).to.be.true; + }); + + it('creates a root index file', () => { + const md = loadMdFile('cli_reference_index.md'); + expect(md.includes('# sf CLI Reference')).to.be.true; + expect(md.includes('./org/cli_reference_org.md')).to.be.true; + }); + + it('creates a root cli reference file', () => { + const md = loadMdFile('cli_reference.md'); + expect(md.includes('# sf CLI Command Reference')).to.be.true; + }); + + it('files use .md extension, not .xml or .ditamap', async () => { + const { readdir } = await import('node:fs/promises'); + const rootFiles = await readdir(testFilesPath); + expect(rootFiles.some((f) => f.endsWith('.xml'))).to.be.false; + expect(rootFiles.some((f) => f.endsWith('.ditamap'))).to.be.false; + expect(rootFiles.some((f) => f.endsWith('.md'))).to.be.true; + }); + + it('filenames do not contain the _unified suffix', () => { + const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); + expect(md).to.be.a('string'); + // Verify the file exists at the unsuffixed path (the load above would throw if not) + }); +}); From 94cbc487ee3d1865e26ab88b50c4e868bf2cc6c0 Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Wed, 6 May 2026 15:33:35 -0700 Subject: [PATCH 2/9] fix: more changes --- src/markdown/command.ts | 34 ++++++++------ test/tmp-md/cli_reference.md | 2 +- .../org/cli_reference_org_assign_permset.md | 32 ++++++------- ...cli_reference_org_assign_permsetlicense.md | 32 ++++++------- .../org/cli_reference_org_create_user.md | 38 +++++++-------- .../org/cli_reference_org_display_user.md | 26 +++++------ .../cli_reference_org_generate_password.md | 38 +++++++-------- .../tmp-md/org/cli_reference_org_list_auth.md | 18 ++++---- .../org/cli_reference_org_list_users.md | 26 +++++------ .../cli_reference_org_login_access-token.md | 30 ++++++------ .../tmp-md/org/cli_reference_org_login_jwt.md | 40 ++++++++-------- .../org/cli_reference_org_login_sfdx-url.md | 36 +++++++-------- .../tmp-md/org/cli_reference_org_login_web.md | 46 +++++++++---------- test/tmp-md/org/cli_reference_org_logout.md | 34 +++++++------- 14 files changed, 218 insertions(+), 214 deletions(-) diff --git a/src/markdown/command.ts b/src/markdown/command.ts index e8e50a61..3e6a4e3d 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -29,6 +29,7 @@ export class MarkdownCommand extends MarkdownBase { private flags: Dictionary; private commandMeta: Record; private commandName: string; + private commandNameForDisplay: string; private summary: string | undefined; private help: string[]; private examples: ParsedExample[]; @@ -52,7 +53,10 @@ export class MarkdownCommand extends MarkdownBase { const binary = readBinary(this.commandMeta); this.summary = punctuate(command.summary); - this.commandName = `${binary} ${command.id.replace(/:/g, asString(this.commandMeta.topicSeparator, ' '))}`; + // commandName is the bare command ID used for template variable replacement (e.g. "agent activate") + // commandNameForDisplay is the full invocation shown in headings (e.g. "sf agent activate") + this.commandName = command.id.replace(/:/g, asString(this.commandMeta.topicSeparator, ' ')); + this.commandNameForDisplay = `${binary} ${this.commandName}`; const description = command.description ? replaceConfigVariables(command.description, binary, this.commandName) @@ -89,7 +93,7 @@ export class MarkdownCommand extends MarkdownBase { lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); lines.push(''); - lines.push(`# ${this.commandName}`); + lines.push(`# ${this.commandNameForDisplay}`); lines.push(''); if (this.summary) { @@ -115,7 +119,7 @@ export class MarkdownCommand extends MarkdownBase { } if (this.help.length > 0) { - lines.push('## Description'); + lines.push(`## Description for ${this.commandName}`); lines.push(''); for (const paragraph of this.help) { lines.push(paragraph); @@ -123,19 +127,8 @@ export class MarkdownCommand extends MarkdownBase { } } - if (parameters.length > 0) { - lines.push('## Flags'); - lines.push(''); - lines.push('| Flag | Description |'); - lines.push('|------|-------------|'); - for (const param of parameters) { - lines.push(renderFlagRow(param)); - } - lines.push(''); - } - if (this.examples.length > 0) { - lines.push('## Examples'); + lines.push(`## Examples for ${this.commandName}`); lines.push(''); for (const example of this.examples) { if (example.description) { @@ -151,6 +144,17 @@ export class MarkdownCommand extends MarkdownBase { } } + if (parameters.length > 0) { + lines.push('## Flags'); + lines.push(''); + lines.push('| Flag | Description |'); + lines.push('|------|-------------|'); + for (const param of parameters) { + lines.push(renderFlagRow(param)); + } + lines.push(''); + } + return lines.join('\n'); } } diff --git a/test/tmp-md/cli_reference.md b/test/tmp-md/cli_reference.md index 9aa3990b..0c13bbc4 100644 --- a/test/tmp-md/cli_reference.md +++ b/test/tmp-md/cli_reference.md @@ -11,4 +11,4 @@ CLI version: `3.1.95` | Plugin | Version | | ------------------------- | -------- | | `@salesforce/plugin-auth` | `3.9.26` | -| `@salesforce/plugin-user` | `3.6.44` | +| `@salesforce/plugin-user` | `3.9.1` | diff --git a/test/tmp-md/org/cli_reference_org_assign_permset.md b/test/tmp-md/org/cli_reference_org_assign_permset.md index ef4a44ce..16b9b796 100644 --- a/test/tmp-md/org/cli_reference_org_assign_permset.md +++ b/test/tmp-md/org/cli_reference_org_assign_permset.md @@ -4,39 +4,39 @@ Assign a permission set to one or more org users. -## Description +## Description for org assign permset To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-n`, `--name NAME` | **Required.** Permission set to assign. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Username or alias to assign the permission set to. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org assign permset Assign two permission sets called DreamHouse and CloudHouse to original admin user of your default org: ```shell -sf sf org assign permset --name DreamHouse --name CloudHouse +sf org assign permset --name DreamHouse --name CloudHouse ``` Assign the Dreamhouse permission set to the original admin user of the org with alias "my-scratch": ```shell -sf sf org assign permset --name DreamHouse --target-org my-scratch +sf org assign permset --name DreamHouse --target-org my-scratch ``` Assign the Dreamhouse permission set to the specified list of users of your default org: ```shell -sf sf org assign permset --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user +sf org assign permset --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user ``` + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-n`, `--name NAME` | **Required.** Permission set to assign. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Username or alias to assign the permission set to. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md b/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md index 99face1e..a91e92f7 100644 --- a/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md +++ b/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md @@ -4,39 +4,39 @@ Assign a permission set license to one or more org users. -## Description +## Description for org assign permsetlicense To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-n`, `--name NAME` | **Required.** Name of the permission set license to assign. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Usernames or alias to assign the permission set license to. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org assign permsetlicense Assign the DreamHouse permission set license to original admin user of your default org: ```shell -sf sf org assign permsetlicense --name DreamHouse +sf org assign permsetlicense --name DreamHouse ``` Assign two permission set licenses to the original admin user of the org with alias "my-scratch": ```shell -sf sf org assign permsetlicense --name DreamHouse --name CloudHouse --target-org my-scratch +sf org assign permsetlicense --name DreamHouse --name CloudHouse --target-org my-scratch ``` Assign the Dreamhouse permission set license to the specified list of users of your default org: ```shell -sf sf org assign permsetlicense --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user3 +sf org assign permsetlicense --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user3 ``` + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-n`, `--name NAME` | **Required.** Name of the permission set license to assign. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Usernames or alias to assign the permission set license to. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_create_user.md b/test/tmp-md/org/cli_reference_org_create_user.md index edf1e130..f9bc1ea5 100644 --- a/test/tmp-md/org/cli_reference_org_create_user.md +++ b/test/tmp-md/org/cli_reference_org_create_user.md @@ -4,11 +4,11 @@ Create a user for a scratch org. -## Description +## Description for org create user A scratch org includes one administrator user by default. For testing purposes, however, you sometimes need to create additional users. -The easiest way to create a user is to let this command assign default or generated characteristics to the new user. If you want to customize your new user, create a definition file and specify it with the --definition-file flag. In the file, you can include all the User sObject (SSalesforce object) fields and Salesforce DX-specific options, as described in "User Definition File for Customizing a Scratch Org User" (https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm). You can also specify these options on the command line. +The easiest way to create a user is to let this command assign default or generated characteristics to the new user. If you want to customize your new user, create a definition file and specify it with the --definition-file flag. In the file, you can include all the User sObject (Salesforce object) fields and Salesforce DX-specific options, as described in "User Definition File for Customizing a Scratch Org User" (https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm). You can also specify these options on the command line. If you don't customize your new user, this command creates a user with the following default characteristics: @@ -28,40 +28,40 @@ After the new user has been created, Salesforce CLI automatically authenticates For more information about user limits, defaults, and other considerations when creating a new scratch org user, see https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users.htm. -## Flags - -| Flag | Description | -| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-a`, `--set-alias SET-ALIAS` | Set an alias for the created username to reference in other CLI commands. | -| `-f`, `--definition-file DEFINITION-FILE` | File path to a user definition file for customizing the new user. The user definition file uses JSON format and can include any Salesforce User sObject field and Salesforce DX-specific options. See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm for more information. | -| `-s`, `--set-unique-username` | Force the username, if specified in the definition file or at the command line, to be unique by appending the org ID. The new user’s username must be unique across all Salesforce orgs and in the form of an email address. If you let this command generate a username for you, it's guaranteed to be unique. If you specify an existing username in a definition file, the command fails. Set this flag to force the username to be unique; as a result, the username might be different than what you specify in the definition file. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org create user Create a user for your default scratch org and let this command generate a username, user ID, and other characteristics: ```shell -sf sf org create user +sf org create user ``` Create a user with alias "testuser1" using a user definition file. Set the "profileName" option to "Chatter Free User", which overrides the value in the defintion file if it also exists there. Create the user for the scratch org with alias "my-scratch": ```shell -sf sf org create user --set-alias testuser1 --definition-file config/project-user-def.json profileName='Chatter Free User' --target-org my-scratch +sf org create user --set-alias testuser1 --definition-file config/project-user-def.json profileName='Chatter Free User' --target-org my-scratch ``` Create a user by specifying the username, email, and perm set assignment at the command line; command fails if the username already exists in Salesforce: ```shell -sf sf org create user username=testuser1@my.org email=me@my.org permsets=DreamHouse +sf org create user username=testuser1@my.org email=me@my.org permsets=DreamHouse ``` Create a user with a definition file, set the email value as specified (overriding any value in the definition file), and generate a password for the user. If the username in the definition file isn't unique, the command appends the org ID to make it unique: ```shell -sf sf org create user --definition-file config/project-user-def.json email=me@my.org generatepassword=true --set-unique-username +sf org create user --definition-file config/project-user-def.json email=me@my.org generatepassword=true --set-unique-username ``` + +## Flags + +| Flag | Description | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-a`, `--set-alias SET-ALIAS` | Set an alias for the created username to reference in other CLI commands. | +| `-f`, `--definition-file DEFINITION-FILE` | File path to a user definition file for customizing the new user. The user definition file uses JSON format and can include any Salesforce User sObject field and Salesforce DX-specific options. See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm for more information. | +| `-s`, `--set-unique-username` | Force the username, if specified in the definition file or at the command line, to be unique by appending the org ID. The new user’s username must be unique across all Salesforce orgs and in the form of an email address. If you let this command generate a username for you, it's guaranteed to be unique. If you specify an existing username in a definition file, the command fails. Set this flag to force the username to be unique; as a result, the username might be different than what you specify in the definition file. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_display_user.md b/test/tmp-md/org/cli_reference_org_display_user.md index 258d683b..fe07e50e 100644 --- a/test/tmp-md/org/cli_reference_org_display_user.md +++ b/test/tmp-md/org/cli_reference_org_display_user.md @@ -4,29 +4,29 @@ Display information about a Salesforce user. -## Description +## Description for org display user Output includes the profile name, org ID, access token, instance URL, login URL, and alias if applicable. The displayed alias is local and different from the Alias field of the User sObject record of the new user, which you set in the Setup UI. -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org display user Display information about the admin user of your default scratch org: ```shell -sf sf org display user +sf org display user ``` Display information about the specified user and output in JSON format: ```shell -sf sf org display user --target-org me@my.org --json +sf org display user --target-org me@my.org --json ``` + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_generate_password.md b/test/tmp-md/org/cli_reference_org_generate_password.md index 71059e49..dfad269b 100644 --- a/test/tmp-md/org/cli_reference_org_generate_password.md +++ b/test/tmp-md/org/cli_reference_org_generate_password.md @@ -4,7 +4,7 @@ Generate a random password for scratch org users. -## Description +## Description for org generate password By default, new scratch orgs contain one admin user with no password. Use this command to generate or change a password for this admin user. After it's set, you can’t unset a password, you can only change it. @@ -26,40 +26,40 @@ To change the password strength, set the --complexity flag to a value between 0 To see a password that was previously generated, run "org display user". -## Flags - -| Flag | Description | -| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Comma-separated list of usernames or aliases to assign the password to; must have been created locally with the "org create user" command. | -| `-l`, `--length LENGTH` | Number of characters in the generated password; valid values are between 8 and 100. Default: `13`. | -| `-c`, `--complexity COMPLEXITY` | Level of password complexity or strength; the higher the value, the stronger the password. Default: `5`. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org generate password Generate a password for the original admin user of your default scratch org: ```shell -sf sf org generate password +sf org generate password ``` -Generate a password that contains 12 characters for the original admin user of the scratch org with alias "my-scratch": +Generate a password that contains 25 characters for the original admin user of the scratch org with alias "my-scratch": ```shell -sf sf org generate password --length 12 --target-org my-scratch +sf org generate password --length 25 --target-org my-scratch ``` Generate a password for your default scratch org admin user that uses lower and upper case letters and numbers only: ```shell -sf sf org generate password --complexity 3 +sf org generate password --complexity 3 ``` Generate a password for the specified users in the default scratch org; these users must have been created locally with the "org create user" command: ```shell -sf sf org generate password --on-behalf-of user1@my.org --on-behalf-of user2@my.org --on-behalf-of user3@my.org +sf org generate password --on-behalf-of user1@my.org --on-behalf-of user2@my.org --on-behalf-of user3@my.org ``` + +## Flags + +| Flag | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-b`, `--on-behalf-of ON-BEHALF-OF` | Comma-separated list of usernames or aliases to assign the password to; must have been created locally with the "org create user" command. | +| `-l`, `--length LENGTH` | Number of characters in the generated password; valid values are between 20 and 100. Default value is 20. Default: `20`. | +| `-c`, `--complexity COMPLEXITY` | Level of password complexity or strength; the higher the value, the stronger the password. Default: `5`. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_list_auth.md b/test/tmp-md/org/cli_reference_org_list_auth.md index 3604f565..0023991d 100644 --- a/test/tmp-md/org/cli_reference_org_list_auth.md +++ b/test/tmp-md/org/cli_reference_org_list_auth.md @@ -4,21 +4,21 @@ List authorization information about the orgs you created or logged into. -## Description +## Description for org list auth This command uses local authorization information that Salesforce CLI caches when you create a scratch org or log into an org. The command doesn't actually connect to the orgs to verify that they're still active. As a result, this command executes very quickly. If you want to view live information about your authorized orgs, such as their connection status, use the "org list" command. +## Examples for org list auth + +List local authorization information about your orgs: + +```shell +sf org list auth +``` + ## Flags | Flag | Description | | ----------------------- | ------------------------------------ | | `--json` | Format output as json. | | `--flags-dir FLAGS-DIR` | Import flag values from a directory. | - -## Examples - -List local authorization information about your orgs: - -```shell -sf sf org list auth -``` diff --git a/test/tmp-md/org/cli_reference_org_list_users.md b/test/tmp-md/org/cli_reference_org_list_users.md index 6ee31575..a4e545aa 100644 --- a/test/tmp-md/org/cli_reference_org_list_users.md +++ b/test/tmp-md/org/cli_reference_org_list_users.md @@ -4,29 +4,29 @@ List all locally-authenticated users of an org. -## Description +## Description for org list users For scratch orgs, the list includes any users you've created with the "org create user" command; the original scratch org admin user is marked with "(A)". For other orgs, the list includes the users you used to authenticate to the org. -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | - -## Examples +## Examples for org list users List the locally-authenticated users of your default org: ```shell -sf sf org list users +sf org list users ``` List the locally-authenticated users of the specified org: ```shell -sf sf org list users --target-org me@my.org +sf org list users --target-org me@my.org ``` + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | +| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_login_access-token.md b/test/tmp-md/org/cli_reference_org_login_access-token.md index 9691c97c..5c952b3d 100644 --- a/test/tmp-md/org/cli_reference_org_login_access-token.md +++ b/test/tmp-md/org/cli_reference_org_login_access-token.md @@ -4,12 +4,26 @@ Authorize an org using an existing Salesforce access token. -## Description +## Description for org login access-token By default, the command runs interactively and asks you for the access token. If you previously authorized the org, the command prompts whether you want to overwrite the local file. Specify --no-prompt to not be prompted. To use the command in a CI/CD script, set the SF_ACCESS_TOKEN environment variable to the access token. Then run the command with the --no-prompt parameter. +## Examples for org login access-token + +Authorize an org on https://mycompany.my.salesforce.com; the command prompts you for the access token: + +```shell +sf org login access-token --instance-url https://mycompany.my.salesforce.com +``` + +Authorize the org without being prompted; you must have previously set the SF_ACCESS_TOKEN environment variable to the access token: + +```shell +sf org login access-token --instance-url https://dev-hub.my.salesforce.com --no-prompt +``` + ## Flags | Flag | Description | @@ -21,17 +35,3 @@ To use the command in a CI/CD script, set the SF_ACCESS_TOKEN environment variab | `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | | `-a`, `--alias ALIAS` | Alias for the org. | | `-p`, `--no-prompt` | Don't prompt for confirmation. | - -## Examples - -Authorize an org on https://mycompany.my.salesforce.com; the command prompts you for the access token: - -```shell -sf sf org login access-token --instance-url https://mycompany.my.salesforce.com -``` - -Authorize the org without being prompted; you must have previously set the SF_ACCESS_TOKEN environment variable to the access token: - -```shell -sf sf org login access-token --instance-url https://dev-hub.my.salesforce.com --no-prompt -``` diff --git a/test/tmp-md/org/cli_reference_org_login_jwt.md b/test/tmp-md/org/cli_reference_org_login_jwt.md index bcfcb9bc..8dbf5c7e 100644 --- a/test/tmp-md/org/cli_reference_org_login_jwt.md +++ b/test/tmp-md/org/cli_reference_org_login_jwt.md @@ -4,7 +4,7 @@ Log in to a Salesforce org using a JSON web token (JWT). -## Description +## Description for org login jwt Use this command in automated environments where you can’t interactively log in with a browser, such as in CI/CD scripts. @@ -22,42 +22,42 @@ See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfd We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. Use --set-default for your default scratch org or sandbox, or --set-default-dev-hub for your default Dev Hub. -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--username USERNAME` | **Required.** Username of the user logging in. | -| `-f`, `--jwt-key-file JWT-KEY-FILE` | **Required.** Path to a file containing the private key. | -| `-i`, `--client-id CLIENT-ID` | **Required.** OAuth client ID (also called consumer key) of your custom connected app. | -| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | - -## Examples +## Examples for org login jwt Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.com). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. ```shell -sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 +sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 ``` Set the org as the default and give it an alias: ```shell -sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default +sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default ``` Set the org as the default Dev Hub and give it an alias: ```shell -sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-dev-hub --set-default-dev-hub +sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-dev-hub --set-default-dev-hub ``` Log in to a sandbox using URL https://MyDomainName--SandboxName.sandbox.my.salesforce.com: ```shell -sf sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com +sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com ``` + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--username USERNAME` | **Required.** Username of the user logging in. | +| `-f`, `--jwt-key-file JWT-KEY-FILE` | **Required.** Path to a file containing the private key. | +| `-i`, `--client-id CLIENT-ID` | **Required.** OAuth client ID (also called consumer key) of your custom connected app. | +| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | diff --git a/test/tmp-md/org/cli_reference_org_login_sfdx-url.md b/test/tmp-md/org/cli_reference_org_login_sfdx-url.md index 3d17348d..82bfee65 100644 --- a/test/tmp-md/org/cli_reference_org_login_sfdx-url.md +++ b/test/tmp-md/org/cli_reference_org_login_sfdx-url.md @@ -4,7 +4,7 @@ Authorize an org using a Salesforce DX authorization URL stored in a file or through standard input (stdin). -## Description +## Description for org login sfdx-url You use the Salesforce DX (SFDX) authorization URL to authorize Salesforce CLI to connect to a target org. The URL contains the required data to accomplish the authorization, such as the client ID, client secret, and instance URL. You must specify the SFDX authorization URL in this format: "force://::@". Replace , , , and with the values specific to your target org. For , don't include a protocol (such as "https://"). Note that although the SFDX authorization URL starts with "force://", it has nothing to do with the actual authorization. Salesforce CLI always communicates with your org using HTTPS. @@ -16,7 +16,7 @@ You have three options when creating the authorization file. The easiest option The resulting JSON file contains the URL in the "sfdxAuthUrl" property of the "result" object. You can then reference the file when running this command: - $ sf sf org login sfdx-url --sfdx-url-file authFile.json + $ sf org login sfdx-url --sfdx-url-file authFile.json NOTE: The "sf org display --verbose" command displays the refresh token only for orgs authorized with the web server flow, and not the JWT bearer flow. @@ -24,34 +24,34 @@ You can also create a JSON file that has a top-level property named sfdxAuthUrl Alternatively, you can pipe the SFDX authorization URL through standard input by specifying the --sfdx-url-stdin flag. -## Flags - -| Flag | Description | -| --------------------------------------- | ----------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-f`, `--sfdx-url-file SFDX-URL-FILE` | Path to a file that contains the Salesforce DX authorization URL. | -| `-u`, `--sfdx-url-stdin SFDX-URL-STDIN` | Pipe the Salesforce DX authorization URL through standard input (stdin). | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | - -## Examples +## Examples for org login sfdx-url Authorize an org using the SFDX authorization URL in the files/authFile.json file: ```shell -sf sf org login sfdx-url --sfdx-url-file files/authFile.json +sf org login sfdx-url --sfdx-url-file files/authFile.json ``` Similar to previous example, but set the org as your default and give it an alias MyDefaultOrg: ```shell -sf sf org login sfdx-url --sfdx-url-file files/authFile.json --set-default --alias MyDefaultOrg +sf org login sfdx-url --sfdx-url-file files/authFile.json --set-default --alias MyDefaultOrg ``` Pipe the SFDX authorization URL from stdin: ```shell -$ echo url | sf sf org login sfdx-url --sfdx-url-stdin +$ echo url | sf org login sfdx-url --sfdx-url-stdin ``` + +## Flags + +| Flag | Description | +| --------------------------------------- | ----------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-f`, `--sfdx-url-file SFDX-URL-FILE` | Path to a file that contains the Salesforce DX authorization URL. | +| `-u`, `--sfdx-url-stdin SFDX-URL-STDIN` | Pipe the Salesforce DX authorization URL through standard input (stdin). | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | diff --git a/test/tmp-md/org/cli_reference_org_login_web.md b/test/tmp-md/org/cli_reference_org_login_web.md index dd09d3e7..6bee397d 100644 --- a/test/tmp-md/org/cli_reference_org_login_web.md +++ b/test/tmp-md/org/cli_reference_org_login_web.md @@ -4,7 +4,7 @@ Log in to a Salesforce org using the web server flow. -## Description +## Description for org login web Opens a Salesforce instance URL in a web browser so you can enter your credentials and log in to your org. After you log in, you can close the browser window. @@ -16,50 +16,50 @@ By default, this command uses the global out-of-the-box connected app in your or You can also use this command to link one or more connected or external client apps in an org to an already-authenticated user. Then Salesforce CLI commands that have API-specific requirements, such as new OAuth scopes or JWT-based access tokens, can use these custom client apps rather than the default one. To create the link, you use the --client-app flag to give the link a name and the --username flag to specify the already-authenticated user. Use the --scopes flag to add OAuth scopes if required. After you create the link, you then use the --client-app value in the other command that has the API-specific requirements. An example of a command that uses this feature is "agent preview"; see the "Preview an Agent" section in the "Agentforce Developer Guide" for details and examples. (https://developer.salesforce.com/docs/einstein/genai/guide/agent-dx-preview.html) -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-b`, `--browser BROWSER` | Browser in which to open the org. If you don’t specify --browser, the command uses your default browser. The exact names of the browser applications differ depending on the operating system you're on; check your documentation for details. Options: `chrome`, `edge`, `firefox`. | -| `-i`, `--client-id CLIENT-ID` | OAuth client ID (also called consumer key) of your custom connected app. | -| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | -| `-c`, `--client-app CLIENT-APP` | Name to give to the link between the connected app or external client and the already-authenticated user. You can specify any string you want. Must be used with --username. | -| `--username USERNAME` | Username of the already-authenticated user to link to the connected app or external client app. Must be used with --client-app. | -| `--scopes SCOPES` | Authentication (OAuth) scopes to request. Use the scope's short name; specify multiple scopes using just one flag instance and separated by spaces: --scopes "sfap_api chatbot_api". | - -## Examples +## Examples for org login web Run the command with no flags to open the default Salesforce login page (https://login.salesforce.com): ```shell -sf sf org login web +sf org login web ``` Log in to your Dev Hub, set it as your default Dev Hub, and set an alias that you reference later when you create a scratch org: ```shell -sf sf org login web --set-default-dev-hub --alias dev-hub +sf org login web --set-default-dev-hub --alias dev-hub ``` Log in to a sandbox and set it as your default org: ```shell -sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default +sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default ``` Use --browser to specify a specific browser, such as Google Chrome: ```shell -sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome +sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome ``` Use your own connected app by specifying its consumer key (also called client ID) and specify additional OAuth scopes: ```shell -sf sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome --client-id 04580y4051234051 --scopes "sfap_api chatbot_api" +sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome --client-id 04580y4051234051 --scopes "sfap_api chatbot_api" ``` + +## Flags + +| Flag | Description | +| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-b`, `--browser BROWSER` | Browser in which to open the org. If you don’t specify --browser, the command uses your default browser. The exact names of the browser applications differ depending on the operating system you're on; check your documentation for details. Options: `chrome`, `edge`, `firefox`. | +| `-i`, `--client-id CLIENT-ID` | OAuth client ID (also called consumer key) of your custom connected app. | +| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | +| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | +| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | +| `-a`, `--alias ALIAS` | Alias for the org. | +| `-c`, `--client-app CLIENT-APP` | Name to give to the link between the connected app or external client and the already-authenticated user. You can specify any string you want. Must be used with --username. | +| `--username USERNAME` | Username of the already-authenticated user to link to the connected app or external client app. Must be used with --client-app. | +| `--scopes SCOPES` | Authentication (OAuth) scopes to request. Use the scope's short name; specify multiple scopes using just one flag instance and separated by spaces: --scopes "sfap_api chatbot_api". | diff --git a/test/tmp-md/org/cli_reference_org_logout.md b/test/tmp-md/org/cli_reference_org_logout.md index a8441714..46473d71 100644 --- a/test/tmp-md/org/cli_reference_org_logout.md +++ b/test/tmp-md/org/cli_reference_org_logout.md @@ -4,7 +4,7 @@ Log out of a Salesforce org. -## Description +## Description for org logout If you run this command with no flags and no default org set in your config or environment, it first displays a list of orgs you've created or logged into, with none of the orgs selected. Use the arrow keys to scroll through the list and the space bar to select the orgs you want to log out of. Press Enter when you're done; the command asks for a final confirmation before logging out of the selected orgs. @@ -14,39 +14,39 @@ Be careful! If you log out of a scratch org without having access to its passwor Use the --client-app flag to log out of the link you previously created between an authenticated user and a connected app or external client app; you create these links with "org login web --client-app". Run "org display" to get the list of client app names. -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | Username or alias of the target org. | -| `-c`, `--client-app CLIENT-APP` | Client app to log out of. | -| `-a`, `--all` | Include all authenticated orgs. All orgs includes Dev Hubs, sandboxes, DE orgs, and expired, deleted, and unknown-status scratch orgs. | -| `-p`, `--no-prompt` | Don't prompt for confirmation. | - -## Examples +## Examples for org logout Interactively select the orgs to log out of: ```shell -sf sf org logout +sf org logout ``` Log out of the org with username me@my.org: ```shell -sf sf org logout --target-org me@my.org +sf org logout --target-org me@my.org ``` Log out of all orgs after confirmation: ```shell -sf sf org logout --all +sf org logout --all ``` Logout of the org with alias my-scratch and don't prompt for confirmation: ```shell -sf sf org logout --target-org my-scratch --no-prompt +sf org logout --target-org my-scratch --no-prompt ``` + +## Flags + +| Flag | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `--json` | Format output as json. | +| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | +| `-o`, `--target-org TARGET-ORG` | Username or alias of the target org. | +| `-c`, `--client-app CLIENT-APP` | Client app to log out of. | +| `-a`, `--all` | Include all authenticated orgs. All orgs includes Dev Hubs, sandboxes, DE orgs, and expired, deleted, and unknown-status scratch orgs. | +| `-p`, `--no-prompt` | Don't prompt for confirmation. | From 8e52e748c9913a41050e484f37a18e3ece63ea3a Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Wed, 6 May 2026 16:40:01 -0700 Subject: [PATCH 3/9] fix: more changes. Go claude code --- src/docs.ts | 22 ++++++++-- src/generator-factory.ts | 33 +++++++++++---- src/markdown/cli-reference.ts | 21 +++++++--- src/markdown/command.ts | 6 +-- src/markdown/index.ts | 1 + src/markdown/root-index.ts | 1 - src/markdown/toc.ts | 65 ++++++++++++++++++++++++++++++ src/markdown/topic-commands.ts | 1 - src/markdown/topic-index.ts | 1 - test/tmp-md/cli_reference.md | 10 +++-- test/tmp-md/cli_reference_index.md | 5 --- test/tmp-md/sfclireference-toc.yml | 33 +++++++++++++++ 12 files changed, 167 insertions(+), 32 deletions(-) create mode 100644 src/markdown/toc.ts delete mode 100644 test/tmp-md/cli_reference_index.md create mode 100644 test/tmp-md/sfclireference-toc.yml diff --git a/src/docs.ts b/src/docs.ts index ab713080..f51a7a1a 100644 --- a/src/docs.ts +++ b/src/docs.ts @@ -18,7 +18,13 @@ import fs from 'node:fs/promises'; import { AnyJson, ensureString } from '@salesforce/ts-types'; import chalk from 'chalk'; import { CliMeta, events, punctuate, SfTopic, SfTopics, CommandClass } from './utils.js'; -import { DitaGeneratorFactory, GeneratorFactory, MarkdownGeneratorFactory, OutputFormat } from './generator-factory.js'; +import { + DitaGeneratorFactory, + GeneratorFactory, + MarkdownGeneratorFactory, + OutputFormat, + TocTopicEntry, +} from './generator-factory.js'; type TopicsByTopicsByTopLevel = Map>; @@ -166,18 +172,28 @@ export class Docs { private async populateTemplate(commands: CommandClass[]): Promise { const topicsAndSubtopics = this.groupTopicsAndSubtopics(commands); - await this.factory.createCliReference().write(); + await this.factory.createCliReference(Array.from(topicsAndSubtopics.keys())).write(); const helpReference = this.factory.createHelpReference(); if (helpReference) await helpReference.write(); - await this.factory.createRootIndex(Array.from(topicsAndSubtopics.keys())).write(); + const rootIndex = this.factory.createRootIndex(Array.from(topicsAndSubtopics.keys())); + if (rootIndex) await rootIndex.write(); + const tocEntries: TocTopicEntry[] = []; for (const [topic, subtopics] of topicsAndSubtopics.entries()) { events.emit('topic', { topic }); // eslint-disable-next-line no-await-in-loop await this.populateTopic(topic, subtopics); + const commandIds = [...subtopics.values()] + .flat() + .filter((cmd) => !cmd.hidden || this.hidden) + .map((cmd) => ({ id: ensureString(cmd.id), state: cmd.state })); + tocEntries.push({ topic, commandIds }); } + + const toc = this.factory.createToc(tocEntries); + if (toc) await toc.write(); } private resolveCommandMeta( diff --git a/src/generator-factory.ts b/src/generator-factory.ts index d12e1f79..0ce8e7e3 100644 --- a/src/generator-factory.ts +++ b/src/generator-factory.ts @@ -23,9 +23,9 @@ import { TopicCommands } from './ditamap/topic-commands.js'; import { TopicDitamap } from './ditamap/topic-ditamap.js'; import { MarkdownCliReference } from './markdown/cli-reference.js'; import { MarkdownCommand } from './markdown/command.js'; -import { MarkdownRootIndex } from './markdown/root-index.js'; import { MarkdownTopicCommands } from './markdown/topic-commands.js'; import { MarkdownTopicIndex } from './markdown/topic-index.js'; +import { MarkdownToc } from './markdown/toc.js'; import { CommandClass, SfTopic } from './utils.js'; export type OutputFormat = 'dita' | 'markdown'; @@ -33,10 +33,16 @@ export type OutputFormat = 'dita' | 'markdown'; type Writable = { write(): Promise }; type WritableWithFilename = Writable & { getFilename(): string }; +export type TocTopicEntry = { + topic: string; + commandIds: Array<{ id: string; state?: string }>; +}; + export type GeneratorFactory = { - createCliReference(): Writable; + createCliReference(topics: string[]): Writable; createHelpReference(): Writable | null; - createRootIndex(topics: string[]): Writable; + createRootIndex(topics: string[]): Writable | null; + createToc(topicEntries: TocTopicEntry[]): Writable | null; createTopicCommands(topic: string, topicMeta: SfTopic): Writable; createTopicIndex(topic: string, commandIds: string[]): Writable; createCommand( @@ -49,7 +55,8 @@ export type GeneratorFactory = { export class DitaGeneratorFactory implements GeneratorFactory { // eslint-disable-next-line class-methods-use-this - public createCliReference(): Writable { + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createCliReference(_topics: string[]): Writable { return new CLIReference(); } @@ -63,6 +70,11 @@ export class DitaGeneratorFactory implements GeneratorFactory { return new BaseDitamap(topics); } + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createToc(_topicEntries: TocTopicEntry[]): null { + return null; + } + // eslint-disable-next-line class-methods-use-this public createTopicCommands(topic: string, topicMeta: SfTopic): Writable { return new TopicCommands(topic, topicMeta); @@ -87,8 +99,8 @@ export class DitaGeneratorFactory implements GeneratorFactory { export class MarkdownGeneratorFactory implements GeneratorFactory { public constructor(private outputDir: string) {} - public createCliReference(): Writable { - return new MarkdownCliReference(Ditamap.cliVersion, Ditamap.pluginVersions, this.outputDir); + public createCliReference(topics: string[]): Writable { + return new MarkdownCliReference(Ditamap.cliVersion, Ditamap.pluginVersions, topics, this.outputDir); } // eslint-disable-next-line class-methods-use-this @@ -96,8 +108,13 @@ export class MarkdownGeneratorFactory implements GeneratorFactory { return null; } - public createRootIndex(topics: string[]): Writable { - return new MarkdownRootIndex(topics, this.outputDir); + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createRootIndex(_topics: string[]): null { + return null; + } + + public createToc(topicEntries: TocTopicEntry[]): Writable { + return new MarkdownToc(topicEntries, this.outputDir); } public createTopicCommands(topic: string, topicMeta: SfTopic): Writable { diff --git a/src/markdown/cli-reference.ts b/src/markdown/cli-reference.ts index 6ec97bea..95a0fde0 100644 --- a/src/markdown/cli-reference.ts +++ b/src/markdown/cli-reference.ts @@ -20,6 +20,7 @@ export class MarkdownCliReference extends MarkdownBase { public constructor( private cliVersion: string, private pluginVersions: Array<{ name: string; version: string }>, + private topics: string[], outputDir: string ) { super(MarkdownBase.file('cli_reference'), outputDir); @@ -27,13 +28,15 @@ export class MarkdownCliReference extends MarkdownBase { protected generate(): Promise { const lines: string[] = []; - lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); + lines.push('# Salesforce CLI Command Reference'); lines.push(''); - lines.push('# sf CLI Command Reference'); + lines.push( + 'This command reference contains information about the Salesforce CLI commands and their flags.' + + ' Use these commands to build Agentforce agents, manage Salesforce DX projects, create and manage' + + ' scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more.' + ); lines.push(''); - lines.push('An alphabetized list of sf CLI commands and their descriptions, arguments, and flags.'); - lines.push(''); - lines.push(`CLI version: \`${this.cliVersion}\``); + lines.push(`Salesforce CLI version: \`${this.cliVersion}\`.`); lines.push(''); if (this.pluginVersions.length > 0) { lines.push('## Plugin Versions'); @@ -45,6 +48,14 @@ export class MarkdownCliReference extends MarkdownBase { } lines.push(''); } + if (this.topics.length > 0) { + lines.push('## Command Topic Index'); + lines.push(''); + for (const topic of this.topics.sort()) { + lines.push(`- [${topic}](./${topic}/cli_reference_${topic}.md)`); + } + lines.push(''); + } return Promise.resolve(lines.join('\n')); } } diff --git a/src/markdown/command.ts b/src/markdown/command.ts index 3e6a4e3d..4074ca6e 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -29,7 +29,6 @@ export class MarkdownCommand extends MarkdownBase { private flags: Dictionary; private commandMeta: Record; private commandName: string; - private commandNameForDisplay: string; private summary: string | undefined; private help: string[]; private examples: ParsedExample[]; @@ -56,7 +55,6 @@ export class MarkdownCommand extends MarkdownBase { // commandName is the bare command ID used for template variable replacement (e.g. "agent activate") // commandNameForDisplay is the full invocation shown in headings (e.g. "sf agent activate") this.commandName = command.id.replace(/:/g, asString(this.commandMeta.topicSeparator, ' ')); - this.commandNameForDisplay = `${binary} ${this.commandName}`; const description = command.description ? replaceConfigVariables(command.description, binary, this.commandName) @@ -91,9 +89,7 @@ export class MarkdownCommand extends MarkdownBase { const lines: string[] = []; - lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); - lines.push(''); - lines.push(`# ${this.commandNameForDisplay}`); + lines.push(`# ${this.commandName}`); lines.push(''); if (this.summary) { diff --git a/src/markdown/index.ts b/src/markdown/index.ts index d37f1a8c..c4f15f7f 100644 --- a/src/markdown/index.ts +++ b/src/markdown/index.ts @@ -20,3 +20,4 @@ export { MarkdownCliReference } from './cli-reference.js'; export { MarkdownRootIndex } from './root-index.js'; export { MarkdownTopicCommands } from './topic-commands.js'; export { MarkdownTopicIndex } from './topic-index.js'; +export { MarkdownToc } from './toc.js'; diff --git a/src/markdown/root-index.ts b/src/markdown/root-index.ts index 946b16b9..b7a01977 100644 --- a/src/markdown/root-index.ts +++ b/src/markdown/root-index.ts @@ -23,7 +23,6 @@ export class MarkdownRootIndex extends MarkdownBase { protected generate(): Promise { const lines: string[] = []; - lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); lines.push(''); lines.push('# sf CLI Reference — Topic Index'); lines.push(''); diff --git a/src/markdown/toc.ts b/src/markdown/toc.ts new file mode 100644 index 00000000..eb61ab3d --- /dev/null +++ b/src/markdown/toc.ts @@ -0,0 +1,65 @@ +/* + * Copyright 2026, Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TocTopicEntry } from '../generator-factory.js'; +import { MarkdownBase } from './markdown-base.js'; + +const STATE_LABELS: Record = { + beta: 'Beta', + preview: 'Preview', + closedPilot: 'Closed Pilot', + openPilot: 'Open Pilot', +}; + +export class MarkdownToc extends MarkdownBase { + public constructor(private topicEntries: TocTopicEntry[], outputDir: string) { + super('sfclireference-toc.yml', outputDir); + } + + public static override file(): string { + return 'sfclireference-toc.yml'; + } + + // eslint-disable-next-line class-methods-use-this + protected generate(): Promise { + const lines: string[] = [ + '- title: Salesforce CLI Command Reference', + ' link: cli_reference.md', + '- title: Release Notes', + ' link: cli_reference_release_notes.md', + '- title: Deprecation Policy', + ' link: cli_reference_deprecation.md', + ]; + + const sorted = [...this.topicEntries].sort((a, b) => a.topic.localeCompare(b.topic)); + + for (const { topic, commandIds } of sorted) { + lines.push(`- title: ${topic} Commands`); + lines.push(` link: ${topic}/cli_reference_${topic}.md`); + lines.push(' topics:'); + for (const { id, state } of [...commandIds].sort((a, b) => a.id.localeCompare(b.id))) { + const commandWithUnderscores = id.replace(/:/g, '_'); + const commandWithSpaces = id.replace(/:/g, ' '); + const stateLabel = state && STATE_LABELS[state] ? ` (${STATE_LABELS[state]})` : ''; + lines.push(` - title: ${commandWithSpaces}${stateLabel}`); + lines.push(` link: ${topic}/cli_reference_${commandWithUnderscores}.md`); + } + } + + lines.push(''); + return Promise.resolve(lines.join('\n')); + } +} diff --git a/src/markdown/topic-commands.ts b/src/markdown/topic-commands.ts index 42859d10..4cd0f1e4 100644 --- a/src/markdown/topic-commands.ts +++ b/src/markdown/topic-commands.ts @@ -27,7 +27,6 @@ export class MarkdownTopicCommands extends MarkdownBase { protected generate(): Promise { const lines: string[] = []; - lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); lines.push(''); lines.push(`# ${this.topic} Commands`); lines.push(''); diff --git a/src/markdown/topic-index.ts b/src/markdown/topic-index.ts index 0a29be9c..819f7ac1 100644 --- a/src/markdown/topic-index.ts +++ b/src/markdown/topic-index.ts @@ -26,7 +26,6 @@ export class MarkdownTopicIndex extends MarkdownBase { protected generate(): Promise { const lines: string[] = []; - lines.push('> **Note:** This file is autogenerated. Do not edit manually.'); lines.push(''); lines.push(`# ${this.topic} Commands`); lines.push(''); diff --git a/test/tmp-md/cli_reference.md b/test/tmp-md/cli_reference.md index 0c13bbc4..ce79f03d 100644 --- a/test/tmp-md/cli_reference.md +++ b/test/tmp-md/cli_reference.md @@ -1,10 +1,10 @@ > **Note:** This file is autogenerated. Do not edit manually. -# sf CLI Command Reference +# Salesforce CLI Command Reference -An alphabetized list of sf CLI commands and their descriptions, arguments, and flags. +This command reference contains information about the Salesforce CLI commands and their flags. Use these commands to build Agentforce agents, manage Salesforce DX projects, create and manage scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more. -CLI version: `3.1.95` +Salesforce CLI version: `3.1.95`. ## Plugin Versions @@ -12,3 +12,7 @@ CLI version: `3.1.95` | ------------------------- | -------- | | `@salesforce/plugin-auth` | `3.9.26` | | `@salesforce/plugin-user` | `3.9.1` | + +## Command Topic Index + +- [org](./org/cli_reference_org.md) diff --git a/test/tmp-md/cli_reference_index.md b/test/tmp-md/cli_reference_index.md deleted file mode 100644 index 685c62db..00000000 --- a/test/tmp-md/cli_reference_index.md +++ /dev/null @@ -1,5 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf CLI Reference — Topic Index - -- [org](./org/cli_reference_org.md) diff --git a/test/tmp-md/sfclireference-toc.yml b/test/tmp-md/sfclireference-toc.yml new file mode 100644 index 00000000..f5579764 --- /dev/null +++ b/test/tmp-md/sfclireference-toc.yml @@ -0,0 +1,33 @@ +- title: Salesforce CLI Command Reference + link: cli_reference.md +- title: Release Notes + link: cli_reference_release_notes.md +- title: Deprecation Policy + link: cli_reference_deprecation.md +- title: org Commands + link: org/cli_reference_org.md + topics: + - title: org assign permset + link: org/cli_reference_org_assign_permset.md + - title: org assign permsetlicense + link: org/cli_reference_org_assign_permsetlicense.md + - title: org create user + link: org/cli_reference_org_create_user.md + - title: org display user + link: org/cli_reference_org_display_user.md + - title: org generate password + link: org/cli_reference_org_generate_password.md + - title: org list auth + link: org/cli_reference_org_list_auth.md + - title: org list users + link: org/cli_reference_org_list_users.md + - title: org login access-token + link: org/cli_reference_org_login_access-token.md + - title: org login jwt + link: org/cli_reference_org_login_jwt.md + - title: org login sfdx-url + link: org/cli_reference_org_login_sfdx-url.md + - title: org login web + link: org/cli_reference_org_login_web.md + - title: org logout + link: org/cli_reference_org_logout.md From 9120041535070e390fd4cb85105b74f37d8b12f4 Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Wed, 6 May 2026 16:42:56 -0700 Subject: [PATCH 4/9] fix: remove smoke tests --- .gitignore | 1 + test/tmp-md/cli_reference.md | 18 ----- test/tmp-md/org/cli_reference_org.md | 16 ----- .../org/cli_reference_org_assign_permset.md | 42 ------------ ...cli_reference_org_assign_permsetlicense.md | 42 ------------ test/tmp-md/org/cli_reference_org_commands.md | 3 - .../org/cli_reference_org_create_user.md | 67 ------------------- .../org/cli_reference_org_display_user.md | 32 --------- .../cli_reference_org_generate_password.md | 65 ------------------ .../tmp-md/org/cli_reference_org_list_auth.md | 24 ------- .../org/cli_reference_org_list_users.md | 32 --------- .../cli_reference_org_login_access-token.md | 37 ---------- .../tmp-md/org/cli_reference_org_login_jwt.md | 63 ----------------- .../org/cli_reference_org_login_sfdx-url.md | 57 ---------------- .../tmp-md/org/cli_reference_org_login_web.md | 65 ------------------ test/tmp-md/org/cli_reference_org_logout.md | 52 -------------- test/tmp-md/sfclireference-toc.yml | 33 --------- 17 files changed, 1 insertion(+), 648 deletions(-) delete mode 100644 test/tmp-md/cli_reference.md delete mode 100644 test/tmp-md/org/cli_reference_org.md delete mode 100644 test/tmp-md/org/cli_reference_org_assign_permset.md delete mode 100644 test/tmp-md/org/cli_reference_org_assign_permsetlicense.md delete mode 100644 test/tmp-md/org/cli_reference_org_commands.md delete mode 100644 test/tmp-md/org/cli_reference_org_create_user.md delete mode 100644 test/tmp-md/org/cli_reference_org_display_user.md delete mode 100644 test/tmp-md/org/cli_reference_org_generate_password.md delete mode 100644 test/tmp-md/org/cli_reference_org_list_auth.md delete mode 100644 test/tmp-md/org/cli_reference_org_list_users.md delete mode 100644 test/tmp-md/org/cli_reference_org_login_access-token.md delete mode 100644 test/tmp-md/org/cli_reference_org_login_jwt.md delete mode 100644 test/tmp-md/org/cli_reference_org_login_sfdx-url.md delete mode 100644 test/tmp-md/org/cli_reference_org_login_web.md delete mode 100644 test/tmp-md/org/cli_reference_org_logout.md delete mode 100644 test/tmp-md/sfclireference-toc.yml diff --git a/.gitignore b/.gitignore index 91b4187d..acf3e601 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ package.json.bak. /tmp /test/tmp +/test/tmp-md diff --git a/test/tmp-md/cli_reference.md b/test/tmp-md/cli_reference.md deleted file mode 100644 index ce79f03d..00000000 --- a/test/tmp-md/cli_reference.md +++ /dev/null @@ -1,18 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# Salesforce CLI Command Reference - -This command reference contains information about the Salesforce CLI commands and their flags. Use these commands to build Agentforce agents, manage Salesforce DX projects, create and manage scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more. - -Salesforce CLI version: `3.1.95`. - -## Plugin Versions - -| Plugin | Version | -| ------------------------- | -------- | -| `@salesforce/plugin-auth` | `3.9.26` | -| `@salesforce/plugin-user` | `3.9.1` | - -## Command Topic Index - -- [org](./org/cli_reference_org.md) diff --git a/test/tmp-md/org/cli_reference_org.md b/test/tmp-md/org/cli_reference_org.md deleted file mode 100644 index 2a50712e..00000000 --- a/test/tmp-md/org/cli_reference_org.md +++ /dev/null @@ -1,16 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# org Commands - -- [org assign permset](./cli_reference_org_assign_permset.md) -- [org assign permsetlicense](./cli_reference_org_assign_permsetlicense.md) -- [org create user](./cli_reference_org_create_user.md) -- [org display user](./cli_reference_org_display_user.md) -- [org generate password](./cli_reference_org_generate_password.md) -- [org list auth](./cli_reference_org_list_auth.md) -- [org list users](./cli_reference_org_list_users.md) -- [org login access-token](./cli_reference_org_login_access-token.md) -- [org login jwt](./cli_reference_org_login_jwt.md) -- [org login sfdx-url](./cli_reference_org_login_sfdx-url.md) -- [org login web](./cli_reference_org_login_web.md) -- [org logout](./cli_reference_org_logout.md) diff --git a/test/tmp-md/org/cli_reference_org_assign_permset.md b/test/tmp-md/org/cli_reference_org_assign_permset.md deleted file mode 100644 index 16b9b796..00000000 --- a/test/tmp-md/org/cli_reference_org_assign_permset.md +++ /dev/null @@ -1,42 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org assign permset - -Assign a permission set to one or more org users. - -## Description for org assign permset - -To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. - -To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. - -## Examples for org assign permset - -Assign two permission sets called DreamHouse and CloudHouse to original admin user of your default org: - -```shell -sf org assign permset --name DreamHouse --name CloudHouse -``` - -Assign the Dreamhouse permission set to the original admin user of the org with alias "my-scratch": - -```shell -sf org assign permset --name DreamHouse --target-org my-scratch -``` - -Assign the Dreamhouse permission set to the specified list of users of your default org: - -```shell -sf org assign permset --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-n`, `--name NAME` | **Required.** Permission set to assign. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Username or alias to assign the permission set to. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md b/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md deleted file mode 100644 index a91e92f7..00000000 --- a/test/tmp-md/org/cli_reference_org_assign_permsetlicense.md +++ /dev/null @@ -1,42 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org assign permsetlicense - -Assign a permission set license to one or more org users. - -## Description for org assign permsetlicense - -To specify an alias for the --target-org or --on-behalf-of flags, use the CLI username alias, such as the one you set with the "alias set" command. Don't use the value of the Alias field of the User Salesforce object for the org user. - -To assign multiple permission sets, either set multiple --name flags or a single --name flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --on-behalf-of. - -## Examples for org assign permsetlicense - -Assign the DreamHouse permission set license to original admin user of your default org: - -```shell -sf org assign permsetlicense --name DreamHouse -``` - -Assign two permission set licenses to the original admin user of the org with alias "my-scratch": - -```shell -sf org assign permsetlicense --name DreamHouse --name CloudHouse --target-org my-scratch -``` - -Assign the Dreamhouse permission set license to the specified list of users of your default org: - -```shell -sf org assign permsetlicense --name DreamHouse --on-behalf-of user1@my.org --on-behalf-of user2 --on-behalf-of user3 -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-n`, `--name NAME` | **Required.** Name of the permission set license to assign. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Usernames or alias to assign the permission set license to. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_commands.md b/test/tmp-md/org/cli_reference_org_commands.md deleted file mode 100644 index 88a3df7c..00000000 --- a/test/tmp-md/org/cli_reference_org_commands.md +++ /dev/null @@ -1,3 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# org Commands diff --git a/test/tmp-md/org/cli_reference_org_create_user.md b/test/tmp-md/org/cli_reference_org_create_user.md deleted file mode 100644 index f9bc1ea5..00000000 --- a/test/tmp-md/org/cli_reference_org_create_user.md +++ /dev/null @@ -1,67 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org create user - -Create a user for a scratch org. - -## Description for org create user - -A scratch org includes one administrator user by default. For testing purposes, however, you sometimes need to create additional users. - -The easiest way to create a user is to let this command assign default or generated characteristics to the new user. If you want to customize your new user, create a definition file and specify it with the --definition-file flag. In the file, you can include all the User sObject (Salesforce object) fields and Salesforce DX-specific options, as described in "User Definition File for Customizing a Scratch Org User" (https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm). You can also specify these options on the command line. - -If you don't customize your new user, this command creates a user with the following default characteristics: - - * The username is the existing administrator’s username prepended with a timestamp, such as 1505759162830_test-wvkpnfm5z113@example.com. - - * The user’s profile is Standard User. - - * The values of the required fields of the User sObject are the corresponding values of the administrator user. - - * The user has no password. - -Use the --set-alias flag to assign a simple name to the user that you can reference in later CLI commands. This alias is local and different from the Alias field of the User sObject record of the new user, which you set in the Setup UI. - -When this command completes, it displays the new username and user ID. Run the "org display user" command to get more information about the new user. - -After the new user has been created, Salesforce CLI automatically authenticates it to the scratch org so the new user can immediately start using the scratch org. The CLI uses the same authentication method that was used on the associated Dev Hub org. Due to Hyperforce limitations, the scratch org user creation fails if the Dev Hub authentication used the JWT flow and the scratch org is on Hyperforce. For this reason, if you plan to create scratch org users, authenticate to the Dev Hub org with either the "org login web" or "org login sfdx-url" command, and not "org login jwt". - -For more information about user limits, defaults, and other considerations when creating a new scratch org user, see https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users.htm. - -## Examples for org create user - -Create a user for your default scratch org and let this command generate a username, user ID, and other characteristics: - -```shell -sf org create user -``` - -Create a user with alias "testuser1" using a user definition file. Set the "profileName" option to "Chatter Free User", which overrides the value in the defintion file if it also exists there. Create the user for the scratch org with alias "my-scratch": - -```shell -sf org create user --set-alias testuser1 --definition-file config/project-user-def.json profileName='Chatter Free User' --target-org my-scratch -``` - -Create a user by specifying the username, email, and perm set assignment at the command line; command fails if the username already exists in Salesforce: - -```shell -sf org create user username=testuser1@my.org email=me@my.org permsets=DreamHouse -``` - -Create a user with a definition file, set the email value as specified (overriding any value in the definition file), and generate a password for the user. If the username in the definition file isn't unique, the command appends the org ID to make it unique: - -```shell -sf org create user --definition-file config/project-user-def.json email=me@my.org generatepassword=true --set-unique-username -``` - -## Flags - -| Flag | Description | -| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-a`, `--set-alias SET-ALIAS` | Set an alias for the created username to reference in other CLI commands. | -| `-f`, `--definition-file DEFINITION-FILE` | File path to a user definition file for customizing the new user. The user definition file uses JSON format and can include any Salesforce User sObject field and Salesforce DX-specific options. See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_users_def_file.htm for more information. | -| `-s`, `--set-unique-username` | Force the username, if specified in the definition file or at the command line, to be unique by appending the org ID. The new user’s username must be unique across all Salesforce orgs and in the form of an email address. If you let this command generate a username for you, it's guaranteed to be unique. If you specify an existing username in a definition file, the command fails. Set this flag to force the username to be unique; as a result, the username might be different than what you specify in the definition file. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_display_user.md b/test/tmp-md/org/cli_reference_org_display_user.md deleted file mode 100644 index fe07e50e..00000000 --- a/test/tmp-md/org/cli_reference_org_display_user.md +++ /dev/null @@ -1,32 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org display user - -Display information about a Salesforce user. - -## Description for org display user - -Output includes the profile name, org ID, access token, instance URL, login URL, and alias if applicable. The displayed alias is local and different from the Alias field of the User sObject record of the new user, which you set in the Setup UI. - -## Examples for org display user - -Display information about the admin user of your default scratch org: - -```shell -sf org display user -``` - -Display information about the specified user and output in JSON format: - -```shell -sf org display user --target-org me@my.org --json -``` - -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_generate_password.md b/test/tmp-md/org/cli_reference_org_generate_password.md deleted file mode 100644 index dfad269b..00000000 --- a/test/tmp-md/org/cli_reference_org_generate_password.md +++ /dev/null @@ -1,65 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org generate password - -Generate a random password for scratch org users. - -## Description for org generate password - -By default, new scratch orgs contain one admin user with no password. Use this command to generate or change a password for this admin user. After it's set, you can’t unset a password, you can only change it. - -You can also use the --on-behalf-of flag to generate a password for a scratch org user that you've created locally with the "org create user" command. This command doesn't work for users you created in the scratch org using Setup. - -To change the password strength, set the --complexity flag to a value between 0 and 5. Each value specifies the types of characters used in the generated password: - -0 - lower case letters only - -1 - lower case letters and numbers only - -2 - lower case letters and symbols only - -3 - lower and upper case letters and numbers only - -4 - lower and upper case letters and symbols only - -5 - lower and upper case letters and numbers and symbols only - -To see a password that was previously generated, run "org display user". - -## Examples for org generate password - -Generate a password for the original admin user of your default scratch org: - -```shell -sf org generate password -``` - -Generate a password that contains 25 characters for the original admin user of the scratch org with alias "my-scratch": - -```shell -sf org generate password --length 25 --target-org my-scratch -``` - -Generate a password for your default scratch org admin user that uses lower and upper case letters and numbers only: - -```shell -sf org generate password --complexity 3 -``` - -Generate a password for the specified users in the default scratch org; these users must have been created locally with the "org create user" command: - -```shell -sf org generate password --on-behalf-of user1@my.org --on-behalf-of user2@my.org --on-behalf-of user3@my.org -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-b`, `--on-behalf-of ON-BEHALF-OF` | Comma-separated list of usernames or aliases to assign the password to; must have been created locally with the "org create user" command. | -| `-l`, `--length LENGTH` | Number of characters in the generated password; valid values are between 20 and 100. Default value is 20. Default: `20`. | -| `-c`, `--complexity COMPLEXITY` | Level of password complexity or strength; the higher the value, the stronger the password. Default: `5`. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_list_auth.md b/test/tmp-md/org/cli_reference_org_list_auth.md deleted file mode 100644 index 0023991d..00000000 --- a/test/tmp-md/org/cli_reference_org_list_auth.md +++ /dev/null @@ -1,24 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org list auth - -List authorization information about the orgs you created or logged into. - -## Description for org list auth - -This command uses local authorization information that Salesforce CLI caches when you create a scratch org or log into an org. The command doesn't actually connect to the orgs to verify that they're still active. As a result, this command executes very quickly. If you want to view live information about your authorized orgs, such as their connection status, use the "org list" command. - -## Examples for org list auth - -List local authorization information about your orgs: - -```shell -sf org list auth -``` - -## Flags - -| Flag | Description | -| ----------------------- | ------------------------------------ | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | diff --git a/test/tmp-md/org/cli_reference_org_list_users.md b/test/tmp-md/org/cli_reference_org_list_users.md deleted file mode 100644 index a4e545aa..00000000 --- a/test/tmp-md/org/cli_reference_org_list_users.md +++ /dev/null @@ -1,32 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org list users - -List all locally-authenticated users of an org. - -## Description for org list users - -For scratch orgs, the list includes any users you've created with the "org create user" command; the original scratch org admin user is marked with "(A)". For other orgs, the list includes the users you used to authenticate to the org. - -## Examples for org list users - -List the locally-authenticated users of your default org: - -```shell -sf org list users -``` - -List the locally-authenticated users of the specified org: - -```shell -sf org list users --target-org me@my.org -``` - -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | **Required.** Username or alias of the target org. Not required if the `target-org` configuration variable is already set. | -| `--api-version API-VERSION` | Override the api version used for api requests made by this command | diff --git a/test/tmp-md/org/cli_reference_org_login_access-token.md b/test/tmp-md/org/cli_reference_org_login_access-token.md deleted file mode 100644 index 5c952b3d..00000000 --- a/test/tmp-md/org/cli_reference_org_login_access-token.md +++ /dev/null @@ -1,37 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org login access-token - -Authorize an org using an existing Salesforce access token. - -## Description for org login access-token - -By default, the command runs interactively and asks you for the access token. If you previously authorized the org, the command prompts whether you want to overwrite the local file. Specify --no-prompt to not be prompted. - -To use the command in a CI/CD script, set the SF_ACCESS_TOKEN environment variable to the access token. Then run the command with the --no-prompt parameter. - -## Examples for org login access-token - -Authorize an org on https://mycompany.my.salesforce.com; the command prompts you for the access token: - -```shell -sf org login access-token --instance-url https://mycompany.my.salesforce.com -``` - -Authorize the org without being prompted; you must have previously set the SF_ACCESS_TOKEN environment variable to the access token: - -```shell -sf org login access-token --instance-url https://dev-hub.my.salesforce.com --no-prompt -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-r`, `--instance-url INSTANCE-URL` | **Required.** URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | -| `-p`, `--no-prompt` | Don't prompt for confirmation. | diff --git a/test/tmp-md/org/cli_reference_org_login_jwt.md b/test/tmp-md/org/cli_reference_org_login_jwt.md deleted file mode 100644 index 8dbf5c7e..00000000 --- a/test/tmp-md/org/cli_reference_org_login_jwt.md +++ /dev/null @@ -1,63 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org login jwt - -Log in to a Salesforce org using a JSON web token (JWT). - -## Description for org login jwt - -Use this command in automated environments where you can’t interactively log in with a browser, such as in CI/CD scripts. - -Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving a project. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. - -Complete these steps before you run this command: - - 1. Create a digital certificate (also called digital signature) and the private key to sign the certificate. You can use your own key and certificate issued by a certification authority. Or use OpenSSL to create a key and a self-signed digital certificate. - - 2. Store the private key in a file on your computer. When you run this command, you set the --jwt-key-file flag to this file. - - 3. Create a custom connected app in your org using the digital certificate. Make note of the consumer key (also called client id) that’s generated for you. Be sure the username of the user logging in is approved to use the connected app. When you run this command, you set the --client-id flag to the consumer key. - -See https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_jwt_flow.htm for more information. - -We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. Use --set-default for your default scratch org or sandbox, or --set-default-dev-hub for your default Dev Hub. - -## Examples for org login jwt - -Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.com). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. - -```shell -sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 -``` - -Set the org as the default and give it an alias: - -```shell -sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default -``` - -Set the org as the default Dev Hub and give it an alias: - -```shell -sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-dev-hub --set-default-dev-hub -``` - -Log in to a sandbox using URL https://MyDomainName--SandboxName.sandbox.my.salesforce.com: - -```shell -sf org login jwt --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 --alias ci-org --set-default --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--username USERNAME` | **Required.** Username of the user logging in. | -| `-f`, `--jwt-key-file JWT-KEY-FILE` | **Required.** Path to a file containing the private key. | -| `-i`, `--client-id CLIENT-ID` | **Required.** OAuth client ID (also called consumer key) of your custom connected app. | -| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | diff --git a/test/tmp-md/org/cli_reference_org_login_sfdx-url.md b/test/tmp-md/org/cli_reference_org_login_sfdx-url.md deleted file mode 100644 index 82bfee65..00000000 --- a/test/tmp-md/org/cli_reference_org_login_sfdx-url.md +++ /dev/null @@ -1,57 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org login sfdx-url - -Authorize an org using a Salesforce DX authorization URL stored in a file or through standard input (stdin). - -## Description for org login sfdx-url - -You use the Salesforce DX (SFDX) authorization URL to authorize Salesforce CLI to connect to a target org. The URL contains the required data to accomplish the authorization, such as the client ID, client secret, and instance URL. You must specify the SFDX authorization URL in this format: "force://::@". Replace , , , and with the values specific to your target org. For , don't include a protocol (such as "https://"). Note that although the SFDX authorization URL starts with "force://", it has nothing to do with the actual authorization. Salesforce CLI always communicates with your org using HTTPS. - -To see an example of an SFDX authorization URL, run "org display --verbose" on an org. - -You have three options when creating the authorization file. The easiest option is to redirect the output of the "sf org display --verbose --json" command into a file. For example, using an org with alias my-org that you've already authorized: - - $ sf org display --target-org my-org --verbose --json > authFile.json - -The resulting JSON file contains the URL in the "sfdxAuthUrl" property of the "result" object. You can then reference the file when running this command: - - $ sf org login sfdx-url --sfdx-url-file authFile.json - -NOTE: The "sf org display --verbose" command displays the refresh token only for orgs authorized with the web server flow, and not the JWT bearer flow. - -You can also create a JSON file that has a top-level property named sfdxAuthUrl whose value is the authorization URL. Finally, you can create a normal text file that includes just the URL and nothing else. - -Alternatively, you can pipe the SFDX authorization URL through standard input by specifying the --sfdx-url-stdin flag. - -## Examples for org login sfdx-url - -Authorize an org using the SFDX authorization URL in the files/authFile.json file: - -```shell -sf org login sfdx-url --sfdx-url-file files/authFile.json -``` - -Similar to previous example, but set the org as your default and give it an alias MyDefaultOrg: - -```shell -sf org login sfdx-url --sfdx-url-file files/authFile.json --set-default --alias MyDefaultOrg -``` - -Pipe the SFDX authorization URL from stdin: - -```shell -$ echo url | sf org login sfdx-url --sfdx-url-stdin -``` - -## Flags - -| Flag | Description | -| --------------------------------------- | ----------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-f`, `--sfdx-url-file SFDX-URL-FILE` | Path to a file that contains the Salesforce DX authorization URL. | -| `-u`, `--sfdx-url-stdin SFDX-URL-STDIN` | Pipe the Salesforce DX authorization URL through standard input (stdin). | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | diff --git a/test/tmp-md/org/cli_reference_org_login_web.md b/test/tmp-md/org/cli_reference_org_login_web.md deleted file mode 100644 index 6bee397d..00000000 --- a/test/tmp-md/org/cli_reference_org_login_web.md +++ /dev/null @@ -1,65 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org login web - -Log in to a Salesforce org using the web server flow. - -## Description for org login web - -Opens a Salesforce instance URL in a web browser so you can enter your credentials and log in to your org. After you log in, you can close the browser window. - -Logging into an org authorizes the CLI to run other commands that connect to that org, such as deploying or retrieving metadata. You can log into many types of orgs, such as sandboxes, Dev Hubs, Env Hubs, production orgs, and scratch orgs. - -We recommend that you set an alias when you log into an org. Aliases make it easy to later reference this org when running commands that require it. If you don’t set an alias, you use the username that you specified when you logged in to the org. If you run multiple commands that reference the same org, consider setting the org as your default. Use --set-default for your default scratch org or sandbox, or --set-default-dev-hub for your default Dev Hub. - -By default, this command uses the global out-of-the-box connected app in your org. If you need more security or control, such as setting the refresh token timeout or specifying IP ranges, create your own connected app using a digital certificate. Make note of the consumer key (also called cliend id) that’s generated for you. Then specify the consumer key with the --client-id flag. - -You can also use this command to link one or more connected or external client apps in an org to an already-authenticated user. Then Salesforce CLI commands that have API-specific requirements, such as new OAuth scopes or JWT-based access tokens, can use these custom client apps rather than the default one. To create the link, you use the --client-app flag to give the link a name and the --username flag to specify the already-authenticated user. Use the --scopes flag to add OAuth scopes if required. After you create the link, you then use the --client-app value in the other command that has the API-specific requirements. An example of a command that uses this feature is "agent preview"; see the "Preview an Agent" section in the "Agentforce Developer Guide" for details and examples. (https://developer.salesforce.com/docs/einstein/genai/guide/agent-dx-preview.html) - -## Examples for org login web - -Run the command with no flags to open the default Salesforce login page (https://login.salesforce.com): - -```shell -sf org login web -``` - -Log in to your Dev Hub, set it as your default Dev Hub, and set an alias that you reference later when you create a scratch org: - -```shell -sf org login web --set-default-dev-hub --alias dev-hub -``` - -Log in to a sandbox and set it as your default org: - -```shell -sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default -``` - -Use --browser to specify a specific browser, such as Google Chrome: - -```shell -sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome -``` - -Use your own connected app by specifying its consumer key (also called client ID) and specify additional OAuth scopes: - -```shell -sf org login web --instance-url https://MyDomainName--SandboxName.sandbox.my.salesforce.com --set-default --browser chrome --client-id 04580y4051234051 --scopes "sfap_api chatbot_api" -``` - -## Flags - -| Flag | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-b`, `--browser BROWSER` | Browser in which to open the org. If you don’t specify --browser, the command uses your default browser. The exact names of the browser applications differ depending on the operating system you're on; check your documentation for details. Options: `chrome`, `edge`, `firefox`. | -| `-i`, `--client-id CLIENT-ID` | OAuth client ID (also called consumer key) of your custom connected app. | -| `-r`, `--instance-url INSTANCE-URL` | URL of the instance that the org lives on. If you specify an --instance-url value, this value overrides the sfdcLoginUrl value in your sfdx-project.json file. To specify a My Domain URL, use the format "https://.my.salesforce.com". To specify a sandbox, set --instance-url to "https://--.sandbox.my.salesforce.com". | -| `-d`, `--set-default-dev-hub` | Set the authenticated org as the default Dev Hub. | -| `-s`, `--set-default` | Set the authenticated org as the default that all org-related commands run against. | -| `-a`, `--alias ALIAS` | Alias for the org. | -| `-c`, `--client-app CLIENT-APP` | Name to give to the link between the connected app or external client and the already-authenticated user. You can specify any string you want. Must be used with --username. | -| `--username USERNAME` | Username of the already-authenticated user to link to the connected app or external client app. Must be used with --client-app. | -| `--scopes SCOPES` | Authentication (OAuth) scopes to request. Use the scope's short name; specify multiple scopes using just one flag instance and separated by spaces: --scopes "sfap_api chatbot_api". | diff --git a/test/tmp-md/org/cli_reference_org_logout.md b/test/tmp-md/org/cli_reference_org_logout.md deleted file mode 100644 index 46473d71..00000000 --- a/test/tmp-md/org/cli_reference_org_logout.md +++ /dev/null @@ -1,52 +0,0 @@ -> **Note:** This file is autogenerated. Do not edit manually. - -# sf org logout - -Log out of a Salesforce org. - -## Description for org logout - -If you run this command with no flags and no default org set in your config or environment, it first displays a list of orgs you've created or logged into, with none of the orgs selected. Use the arrow keys to scroll through the list and the space bar to select the orgs you want to log out of. Press Enter when you're done; the command asks for a final confirmation before logging out of the selected orgs. - -The process is similar if you specify --all, except that in the initial list of orgs, they're all selected. Use --target-org to logout of a specific org. In both these cases by default, you must still confirm that you want to log out. Use --no-prompt to never be asked for confirmation when also using --all or --target-org. - -Be careful! If you log out of a scratch org without having access to its password, you can't access the scratch org again, either through the CLI or the Salesforce UI. - -Use the --client-app flag to log out of the link you previously created between an authenticated user and a connected app or external client app; you create these links with "org login web --client-app". Run "org display" to get the list of client app names. - -## Examples for org logout - -Interactively select the orgs to log out of: - -```shell -sf org logout -``` - -Log out of the org with username me@my.org: - -```shell -sf org logout --target-org me@my.org -``` - -Log out of all orgs after confirmation: - -```shell -sf org logout --all -``` - -Logout of the org with alias my-scratch and don't prompt for confirmation: - -```shell -sf org logout --target-org my-scratch --no-prompt -``` - -## Flags - -| Flag | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -| `--json` | Format output as json. | -| `--flags-dir FLAGS-DIR` | Import flag values from a directory. | -| `-o`, `--target-org TARGET-ORG` | Username or alias of the target org. | -| `-c`, `--client-app CLIENT-APP` | Client app to log out of. | -| `-a`, `--all` | Include all authenticated orgs. All orgs includes Dev Hubs, sandboxes, DE orgs, and expired, deleted, and unknown-status scratch orgs. | -| `-p`, `--no-prompt` | Don't prompt for confirmation. | diff --git a/test/tmp-md/sfclireference-toc.yml b/test/tmp-md/sfclireference-toc.yml deleted file mode 100644 index f5579764..00000000 --- a/test/tmp-md/sfclireference-toc.yml +++ /dev/null @@ -1,33 +0,0 @@ -- title: Salesforce CLI Command Reference - link: cli_reference.md -- title: Release Notes - link: cli_reference_release_notes.md -- title: Deprecation Policy - link: cli_reference_deprecation.md -- title: org Commands - link: org/cli_reference_org.md - topics: - - title: org assign permset - link: org/cli_reference_org_assign_permset.md - - title: org assign permsetlicense - link: org/cli_reference_org_assign_permsetlicense.md - - title: org create user - link: org/cli_reference_org_create_user.md - - title: org display user - link: org/cli_reference_org_display_user.md - - title: org generate password - link: org/cli_reference_org_generate_password.md - - title: org list auth - link: org/cli_reference_org_list_auth.md - - title: org list users - link: org/cli_reference_org_list_users.md - - title: org login access-token - link: org/cli_reference_org_login_access-token.md - - title: org login jwt - link: org/cli_reference_org_login_jwt.md - - title: org login sfdx-url - link: org/cli_reference_org_login_sfdx-url.md - - title: org login web - link: org/cli_reference_org_login_web.md - - title: org logout - link: org/cli_reference_org_logout.md From a8b6c881ed112287a1d13e0f7a776e70949b538c Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Wed, 6 May 2026 16:46:12 -0700 Subject: [PATCH 5/9] fix: fix problems --- package.json | 5 +++-- test/unit/markdown.test.ts | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 4bf22ca8..d3edace0 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,8 @@ ], "output": [], "dependencies": [ - "test:command-reference" + "test:command-reference", + "test:command-reference-markdown" ] }, "test:command-reference": { @@ -198,7 +199,7 @@ "output": [] }, "test:command-reference-markdown": { - "command": "node --loader ts-node/esm --no-warnings=ExperimentalWarning \"./bin/dev.js\" commandreference generate --plugins auth --plugins user --output-format markdown --outputdir test/tmp-md", + "command": "node --loader ts-node/esm --no-warnings=ExperimentalWarning \"./bin/dev.js\" commandreference generate --plugins auth --plugins user --output-format markdown --output-dir test/tmp-md", "files": [ "src/**/*.ts", "messages/**", diff --git a/test/unit/markdown.test.ts b/test/unit/markdown.test.ts index b6e708cd..7ba6910b 100644 --- a/test/unit/markdown.test.ts +++ b/test/unit/markdown.test.ts @@ -47,7 +47,7 @@ describe('markdown output: plugin-auth and user', () => { it('creates a command file with the correct H1 heading', () => { const md = loadMdFile(join('org', 'cli_reference_org_login_jwt.md')); - expect(md.includes('# sf org login jwt')).to.be.true; + expect(md.includes('# org login jwt')).to.be.true; }); it('includes the command summary', () => { @@ -86,15 +86,15 @@ describe('markdown output: plugin-auth and user', () => { expect(md.includes('# org Commands')).to.be.true; }); - it('creates a root index file', () => { - const md = loadMdFile('cli_reference_index.md'); - expect(md.includes('# sf CLI Reference')).to.be.true; - expect(md.includes('./org/cli_reference_org.md')).to.be.true; + it('creates a toc file', () => { + const toc = loadMdFile('sfclireference-toc.yml'); + expect(toc.includes('- title: Salesforce CLI Command Reference')).to.be.true; + expect(toc.includes('org/cli_reference_org.md')).to.be.true; }); it('creates a root cli reference file', () => { const md = loadMdFile('cli_reference.md'); - expect(md.includes('# sf CLI Command Reference')).to.be.true; + expect(md.includes('# Salesforce CLI Command Reference')).to.be.true; }); it('files use .md extension, not .xml or .ditamap', async () => { From cb6cf4bb1828968b6079da595f2c736dc6987686 Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Thu, 7 May 2026 10:21:05 -0700 Subject: [PATCH 6/9] fix: more finessing --- src/docs.ts | 7 ++- src/generator-factory.ts | 26 ++++----- src/markdown/cli-reference.ts | 11 +--- src/markdown/command.ts | 100 ++++++++++++++++++++++++++-------- src/markdown/toc.ts | 11 +++- src/markdown/topic-index.ts | 13 ++++- test/unit/markdown.test.ts | 7 +-- 7 files changed, 114 insertions(+), 61 deletions(-) diff --git a/src/docs.ts b/src/docs.ts index f51a7a1a..c48cac0a 100644 --- a/src/docs.ts +++ b/src/docs.ts @@ -109,8 +109,9 @@ export class Docs { // The topic ditamap with all of the subtopic links. events.emit('subtopics', topic, subTopicNames); - await this.factory.createTopicCommands(topic, topicMeta).write(); - await this.factory.createTopicIndex(topic, commandIds).write(); + const topicCommands = this.factory.createTopicCommands(topic, topicMeta); + if (topicCommands) await topicCommands.write(); + await this.factory.createTopicIndex(topic, commandIds, topicMeta).write(); return subTopicNames; } @@ -188,7 +189,7 @@ export class Docs { const commandIds = [...subtopics.values()] .flat() .filter((cmd) => !cmd.hidden || this.hidden) - .map((cmd) => ({ id: ensureString(cmd.id), state: cmd.state })); + .map((cmd) => ({ id: ensureString(cmd.id), state: cmd.state, deprecated: cmd.deprecated ?? false })); tocEntries.push({ topic, commandIds }); } diff --git a/src/generator-factory.ts b/src/generator-factory.ts index 0ce8e7e3..056808e0 100644 --- a/src/generator-factory.ts +++ b/src/generator-factory.ts @@ -23,7 +23,6 @@ import { TopicCommands } from './ditamap/topic-commands.js'; import { TopicDitamap } from './ditamap/topic-ditamap.js'; import { MarkdownCliReference } from './markdown/cli-reference.js'; import { MarkdownCommand } from './markdown/command.js'; -import { MarkdownTopicCommands } from './markdown/topic-commands.js'; import { MarkdownTopicIndex } from './markdown/topic-index.js'; import { MarkdownToc } from './markdown/toc.js'; import { CommandClass, SfTopic } from './utils.js'; @@ -35,7 +34,7 @@ type WritableWithFilename = Writable & { getFilename(): string }; export type TocTopicEntry = { topic: string; - commandIds: Array<{ id: string; state?: string }>; + commandIds: Array<{ id: string; state?: string; deprecated?: boolean }>; }; export type GeneratorFactory = { @@ -43,8 +42,8 @@ export type GeneratorFactory = { createHelpReference(): Writable | null; createRootIndex(topics: string[]): Writable | null; createToc(topicEntries: TocTopicEntry[]): Writable | null; - createTopicCommands(topic: string, topicMeta: SfTopic): Writable; - createTopicIndex(topic: string, commandIds: string[]): Writable; + createTopicCommands(topic: string, topicMeta: SfTopic): Writable | null; + createTopicIndex(topic: string, commandIds: string[], topicMeta: SfTopic): Writable; createCommand( topic: string, subtopic: string | null, @@ -54,7 +53,6 @@ export type GeneratorFactory = { }; export class DitaGeneratorFactory implements GeneratorFactory { - // eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars public createCliReference(_topics: string[]): Writable { return new CLIReference(); @@ -80,8 +78,8 @@ export class DitaGeneratorFactory implements GeneratorFactory { return new TopicCommands(topic, topicMeta); } - // eslint-disable-next-line class-methods-use-this - public createTopicIndex(topic: string, commandIds: string[]): Writable { + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createTopicIndex(topic: string, commandIds: string[], _topicMeta: SfTopic): Writable { return new TopicDitamap(topic, commandIds); } @@ -99,8 +97,9 @@ export class DitaGeneratorFactory implements GeneratorFactory { export class MarkdownGeneratorFactory implements GeneratorFactory { public constructor(private outputDir: string) {} - public createCliReference(topics: string[]): Writable { - return new MarkdownCliReference(Ditamap.cliVersion, Ditamap.pluginVersions, topics, this.outputDir); + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createCliReference(_topics: string[]): Writable { + return new MarkdownCliReference(Ditamap.cliVersion, Ditamap.pluginVersions, this.outputDir); } // eslint-disable-next-line class-methods-use-this @@ -117,12 +116,13 @@ export class MarkdownGeneratorFactory implements GeneratorFactory { return new MarkdownToc(topicEntries, this.outputDir); } - public createTopicCommands(topic: string, topicMeta: SfTopic): Writable { - return new MarkdownTopicCommands(topic, topicMeta, this.outputDir); + // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars + public createTopicCommands(_topic: string, _topicMeta: SfTopic): null { + return null; } - public createTopicIndex(topic: string, commandIds: string[]): Writable { - return new MarkdownTopicIndex(topic, commandIds, this.outputDir); + public createTopicIndex(topic: string, commandIds: string[], topicMeta: SfTopic): Writable { + return new MarkdownTopicIndex(topic, commandIds, topicMeta, this.outputDir); } public createCommand( diff --git a/src/markdown/cli-reference.ts b/src/markdown/cli-reference.ts index 95a0fde0..d96f4d7a 100644 --- a/src/markdown/cli-reference.ts +++ b/src/markdown/cli-reference.ts @@ -20,7 +20,6 @@ export class MarkdownCliReference extends MarkdownBase { public constructor( private cliVersion: string, private pluginVersions: Array<{ name: string; version: string }>, - private topics: string[], outputDir: string ) { super(MarkdownBase.file('cli_reference'), outputDir); @@ -36,7 +35,7 @@ export class MarkdownCliReference extends MarkdownBase { ' scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more.' ); lines.push(''); - lines.push(`Salesforce CLI version: \`${this.cliVersion}\`.`); + lines.push(`Salesforce CLI version: \`${this.cliVersion}\``); lines.push(''); if (this.pluginVersions.length > 0) { lines.push('## Plugin Versions'); @@ -48,14 +47,6 @@ export class MarkdownCliReference extends MarkdownBase { } lines.push(''); } - if (this.topics.length > 0) { - lines.push('## Command Topic Index'); - lines.push(''); - for (const topic of this.topics.sort()) { - lines.push(`- [${topic}](./${topic}/cli_reference_${topic}.md)`); - } - lines.push(''); - } return Promise.resolve(lines.join('\n')); } } diff --git a/src/markdown/command.ts b/src/markdown/command.ts index 4074ca6e..52fcf573 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -34,6 +34,7 @@ export class MarkdownCommand extends MarkdownBase { private examples: ParsedExample[]; private state: unknown; private deprecated: boolean; + private deprecationDetails: { version?: string; to?: string } | null; public constructor( topic: string, @@ -81,6 +82,8 @@ export class MarkdownCommand extends MarkdownBase { this.state = command.state ?? this.commandMeta.state; this.deprecated = (command.deprecated as boolean) ?? this.state === 'deprecated' ?? false; + const dep = command.deprecated; + this.deprecationDetails = dep && typeof dep === 'object' ? (dep as { version?: string; to?: string }) : null; } protected async generate(): Promise { @@ -89,7 +92,8 @@ export class MarkdownCommand extends MarkdownBase { const lines: string[] = []; - lines.push(`# ${this.commandName}`); + const stateLabel = resolveStateLabel(this.state, this.deprecated); + lines.push(`# ${this.commandName}${stateLabel ? ` (${stateLabel})` : ''}`); lines.push(''); if (this.summary) { @@ -97,20 +101,11 @@ export class MarkdownCommand extends MarkdownBase { lines.push(''); } - if (this.deprecated) { - lines.push('> **Deprecated**'); - lines.push(''); - } else if (this.state === 'beta') { - lines.push('> **Beta**'); - lines.push(''); - } else if (this.state === 'preview') { - lines.push('> **Preview**'); - lines.push(''); - } else if (this.state === 'closedPilot') { - lines.push('> **Closed Pilot**'); - lines.push(''); - } else if (this.state === 'openPilot') { - lines.push('> **Open Pilot**'); + const disclaimer = resolveDisclaimer(this.commandName, this.state, this.deprecated, this.deprecationDetails); + if (disclaimer) { + lines.push(':::note'); + lines.push(disclaimer); + lines.push(':::'); lines.push(''); } @@ -118,7 +113,7 @@ export class MarkdownCommand extends MarkdownBase { lines.push(`## Description for ${this.commandName}`); lines.push(''); for (const paragraph of this.help) { - lines.push(paragraph); + lines.push(applyCodeFormatting(escapeAngleBrackets(paragraph))); lines.push(''); } } @@ -144,7 +139,7 @@ export class MarkdownCommand extends MarkdownBase { lines.push('## Flags'); lines.push(''); lines.push('| Flag | Description |'); - lines.push('|------|-------------|'); + lines.push('|----------------------------------------|-------------|'); for (const param of parameters) { lines.push(renderFlagRow(param)); } @@ -155,6 +150,58 @@ export class MarkdownCommand extends MarkdownBase { } } +function escapeAngleBrackets(text: string): string { + return text.replace(//g, '>'); +} + +function applyCodeFormatting(text: string): string { + // Wrap --flag-name tokens (not already in backticks) + let result = text.replace(/(? `\`${o}\``).join(', ')}.`); if (param.deprecated) { - parts.push(`Deprecated${param.deprecated.to ? `, use \`--${param.deprecated.to}\`` : ''}.`); + const toNote = param.deprecated.to ? ` Use \`--${param.deprecated.to}\` instead.` : ''; + parts.push(`**This flag is deprecated.${toNote}**`); } - return parts.join(' ').replace(/\n/g, ' '); + if (!param.optional) parts.push('**Required**'); + if (param.options?.length) { + parts.push(`**Valid Values:** ${param.options.map((o) => `\`${o}\``).join(', ')}`); + } + if (param.defaultFlagValue) parts.push(`**Default value:** \`${param.defaultFlagValue}\``); + const desc = param.description + .map((p) => applyCodeFormatting(escapeAngleBrackets(p.replace(/\|/g, '|')))) + .join('

'); + if (desc) parts.push(desc); + return parts.join('
').replace(/\n/g, ' '); } diff --git a/src/markdown/toc.ts b/src/markdown/toc.ts index eb61ab3d..13459d48 100644 --- a/src/markdown/toc.ts +++ b/src/markdown/toc.ts @@ -19,9 +19,10 @@ import { MarkdownBase } from './markdown-base.js'; const STATE_LABELS: Record = { beta: 'Beta', - preview: 'Preview', + preview: 'Developer Preview', closedPilot: 'Closed Pilot', openPilot: 'Open Pilot', + deprecated: 'Deprecated', }; export class MarkdownToc extends MarkdownBase { @@ -50,10 +51,14 @@ export class MarkdownToc extends MarkdownBase { lines.push(`- title: ${topic} Commands`); lines.push(` link: ${topic}/cli_reference_${topic}.md`); lines.push(' topics:'); - for (const { id, state } of [...commandIds].sort((a, b) => a.id.localeCompare(b.id))) { + for (const { id, state, deprecated } of [...commandIds].sort((a, b) => a.id.localeCompare(b.id))) { const commandWithUnderscores = id.replace(/:/g, '_'); const commandWithSpaces = id.replace(/:/g, ' '); - const stateLabel = state && STATE_LABELS[state] ? ` (${STATE_LABELS[state]})` : ''; + const stateLabel = deprecated + ? ' (Deprecated)' + : state && STATE_LABELS[state] + ? ` (${STATE_LABELS[state]})` + : ''; lines.push(` - title: ${commandWithSpaces}${stateLabel}`); lines.push(` link: ${topic}/cli_reference_${commandWithUnderscores}.md`); } diff --git a/src/markdown/topic-index.ts b/src/markdown/topic-index.ts index 819f7ac1..49bf8c19 100644 --- a/src/markdown/topic-index.ts +++ b/src/markdown/topic-index.ts @@ -15,10 +15,16 @@ */ import { join } from 'node:path'; +import { SfTopic } from '../utils.js'; import { MarkdownBase } from './markdown-base.js'; export class MarkdownTopicIndex extends MarkdownBase { - public constructor(private topic: string, private commandIds: string[], outputDir: string) { + public constructor( + private topic: string, + private commandIds: string[], + private topicMeta: SfTopic, + outputDir: string + ) { const filename = MarkdownBase.file(`cli_reference_${topic}`); super(filename, outputDir); this.destination = join(outputDir, topic, filename); @@ -26,9 +32,12 @@ export class MarkdownTopicIndex extends MarkdownBase { protected generate(): Promise { const lines: string[] = []; - lines.push(''); lines.push(`# ${this.topic} Commands`); lines.push(''); + if (this.topicMeta.description) { + lines.push(this.topicMeta.description); + lines.push(''); + } for (const id of [...this.commandIds].sort()) { const commandWithUnderscores = id.replace(/:/g, '_'); const commandWithSpaces = id.replace(/:/g, ' '); diff --git a/test/unit/markdown.test.ts b/test/unit/markdown.test.ts index 7ba6910b..4eea7969 100644 --- a/test/unit/markdown.test.ts +++ b/test/unit/markdown.test.ts @@ -75,17 +75,12 @@ describe('markdown output: plugin-auth and user', () => { expect(md.includes(' { + it('creates a topic index file with description and command links', () => { const md = loadMdFile(join('org', 'cli_reference_org.md')); expect(md.includes('# org Commands')).to.be.true; expect(md.includes('cli_reference_org_login_jwt.md')).to.be.true; }); - it('creates a topic commands overview file', () => { - const md = loadMdFile(join('org', 'cli_reference_org_commands.md')); - expect(md.includes('# org Commands')).to.be.true; - }); - it('creates a toc file', () => { const toc = loadMdFile('sfclireference-toc.yml'); expect(toc.includes('- title: Salesforce CLI Command Reference')).to.be.true; From ecc80f0732bd7ddb8485c90a1da624533531b63e Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Thu, 7 May 2026 10:47:10 -0700 Subject: [PATCH 7/9] fix: tweaks --- src/markdown/cli-reference.ts | 7 ++++--- src/markdown/command.ts | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/markdown/cli-reference.ts b/src/markdown/cli-reference.ts index d96f4d7a..40823995 100644 --- a/src/markdown/cli-reference.ts +++ b/src/markdown/cli-reference.ts @@ -30,9 +30,7 @@ export class MarkdownCliReference extends MarkdownBase { lines.push('# Salesforce CLI Command Reference'); lines.push(''); lines.push( - 'This command reference contains information about the Salesforce CLI commands and their flags.' + - ' Use these commands to build Agentforce agents, manage Salesforce DX projects, create and manage' + - ' scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more.' + 'This command reference contains information about the Salesforce CLI commands and their flags. Use these commands to build Agentforce agents, manage Salesforce DX projects, create and manage scratch orgs and sandboxes, synchronize source to and from orgs, create and install packages, and more.' ); lines.push(''); lines.push(`Salesforce CLI version: \`${this.cliVersion}\``); @@ -40,12 +38,15 @@ export class MarkdownCliReference extends MarkdownBase { if (this.pluginVersions.length > 0) { lines.push('## Plugin Versions'); lines.push(''); + lines.push(''); lines.push('| Plugin | Version |'); lines.push('|--------|---------|'); for (const { name, version } of this.pluginVersions) { lines.push(`| \`${name}\` | \`${version}\` |`); } lines.push(''); + lines.push(''); + lines.push(''); } return Promise.resolve(lines.join('\n')); } diff --git a/src/markdown/command.ts b/src/markdown/command.ts index 52fcf573..7bd2c044 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -138,12 +138,15 @@ export class MarkdownCommand extends MarkdownBase { if (parameters.length > 0) { lines.push('## Flags'); lines.push(''); + lines.push(''); lines.push('| Flag | Description |'); lines.push('|----------------------------------------|-------------|'); for (const param of parameters) { lines.push(renderFlagRow(param)); } lines.push(''); + lines.push(''); + lines.push(''); } return lines.join('\n'); @@ -157,6 +160,8 @@ function escapeAngleBrackets(text: string): string { function applyCodeFormatting(text: string): string { // Wrap --flag-name tokens (not already in backticks) let result = text.replace(/(? Date: Fri, 8 May 2026 11:49:06 -0700 Subject: [PATCH 8/9] fix: more tweaks --- src/markdown/command.ts | 45 ++++++++++++++++++++++++++++++++----- src/markdown/toc.ts | 6 ++++- src/markdown/topic-index.ts | 6 ++++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/markdown/command.ts b/src/markdown/command.ts index 7bd2c044..d4f46280 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -44,7 +44,13 @@ export class MarkdownCommand extends MarkdownBase { outputDir: string ) { const commandWithUnderscores = ensureString(command.id).replace(/:/g, '_'); - const filename = MarkdownBase.file(`cli_reference_${commandWithUnderscores}`); + // If the command ID has no subtopic (e.g. "doctor"), its filename would collide with the topic + // index file (cli_reference_doctor.md), so append _command to disambiguate. + const isTopicLevelCommand = !ensureString(command.id).includes(':'); + const baseName = isTopicLevelCommand + ? `cli_reference_${commandWithUnderscores}_command` + : `cli_reference_${commandWithUnderscores}`; + const filename = MarkdownBase.file(baseName); super(filename, outputDir); this.destination = join(outputDir, topic, filename); @@ -112,8 +118,10 @@ export class MarkdownCommand extends MarkdownBase { if (this.help.length > 0) { lines.push(`## Description for ${this.commandName}`); lines.push(''); - for (const paragraph of this.help) { - lines.push(applyCodeFormatting(escapeAngleBrackets(paragraph))); + for (const paragraph of convertHyphenListsToMarkdown( + this.help.map((p) => applyCodeFormatting(escapeAngleBrackets(p))) + )) { + lines.push(paragraph); lines.push(''); } } @@ -162,12 +170,37 @@ function applyCodeFormatting(text: string): string { let result = text.replace(/(? for table cell rendering + const items: string[] = []; + while (i < paragraphs.length && paragraphs[i].startsWith('- ')) { + items.push(paragraphs[i]); + i++; + } + result.push(items.join('
')); + } else { + result.push(paragraphs[i]); + i++; + } + } + return result; +} + function resolveStateLabel(state: unknown, deprecated: boolean): string | null { if (deprecated) return 'Deprecated'; if (state === 'beta') return 'Beta'; @@ -232,9 +265,9 @@ function renderFlagDescription(param: CommandParameterData): string { parts.push(`**Valid Values:** ${param.options.map((o) => `\`${o}\``).join(', ')}`); } if (param.defaultFlagValue) parts.push(`**Default value:** \`${param.defaultFlagValue}\``); - const desc = param.description - .map((p) => applyCodeFormatting(escapeAngleBrackets(p.replace(/\|/g, '|')))) - .join('

'); + const desc = convertHyphenListsToMarkdown( + param.description.map((p) => applyCodeFormatting(escapeAngleBrackets(p.replace(/\|/g, '|')))) + ).join('

'); if (desc) parts.push(desc); return parts.join('
').replace(/\n/g, ' '); } diff --git a/src/markdown/toc.ts b/src/markdown/toc.ts index 13459d48..750bbad7 100644 --- a/src/markdown/toc.ts +++ b/src/markdown/toc.ts @@ -59,8 +59,12 @@ export class MarkdownToc extends MarkdownBase { : state && STATE_LABELS[state] ? ` (${STATE_LABELS[state]})` : ''; + const isTopicLevelCommand = !id.includes(':'); + const linkTarget = isTopicLevelCommand + ? `cli_reference_${commandWithUnderscores}_command.md` + : `cli_reference_${commandWithUnderscores}.md`; lines.push(` - title: ${commandWithSpaces}${stateLabel}`); - lines.push(` link: ${topic}/cli_reference_${commandWithUnderscores}.md`); + lines.push(` link: ${topic}/${linkTarget}`); } } diff --git a/src/markdown/topic-index.ts b/src/markdown/topic-index.ts index 49bf8c19..8f18aa3e 100644 --- a/src/markdown/topic-index.ts +++ b/src/markdown/topic-index.ts @@ -41,7 +41,11 @@ export class MarkdownTopicIndex extends MarkdownBase { for (const id of [...this.commandIds].sort()) { const commandWithUnderscores = id.replace(/:/g, '_'); const commandWithSpaces = id.replace(/:/g, ' '); - lines.push(`- [${commandWithSpaces}](./cli_reference_${commandWithUnderscores}.md)`); + const isTopicLevelCommand = !id.includes(':'); + const linkTarget = isTopicLevelCommand + ? `cli_reference_${commandWithUnderscores}_command.md` + : `cli_reference_${commandWithUnderscores}.md`; + lines.push(`- [${commandWithSpaces}](./${linkTarget})`); } lines.push(''); return Promise.resolve(lines.join('\n')); From fbeac6e334e7f062c0cba141d8b803600128b0ba Mon Sep 17 00:00:00 2001 From: Juliet Shackell Date: Fri, 8 May 2026 12:01:45 -0700 Subject: [PATCH 9/9] fix: remove leading $ in examples --- src/markdown/command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/markdown/command.ts b/src/markdown/command.ts index d4f46280..0fb2a94a 100644 --- a/src/markdown/command.ts +++ b/src/markdown/command.ts @@ -136,7 +136,7 @@ export class MarkdownCommand extends MarkdownBase { } for (const cmd of example.commands) { lines.push('```shell'); - lines.push(cmd.trim()); + lines.push(cmd.trim().replace(/^\$\s*/, '')); lines.push('```'); lines.push(''); }