Skip to content

Commit 18a2425

Browse files
committed
Add docs command topic for Script API documentation and XSD schemas
New CLI commands: - `b2c docs search <query>` - Fuzzy search bundled Script API documentation - `b2c docs read <query>` - Read documentation with terminal markdown rendering - `b2c docs schema <query>` - Read XSD schema files with fuzzy matching - `b2c docs download <output>` - Download docs from B2C instance SDK changes: - Add operations/docs module with search, read, and download functions - Bundle 519 Script API markdown files and 54 XSD schemas in data/ - Use createRequire for robust path resolution to bundled data - Export docs operations from main SDK entry point Also adds b2c-docs skill for agent usage examples.
1 parent 29b970a commit 18a2425

596 files changed

Lines changed: 150615 additions & 15 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ pnpm run -r format
3737
pnpm run -r lint
3838
```
3939

40+
## Copyright Header
41+
42+
All TypeScript source files must include this exact copyright header block:
43+
44+
```typescript
45+
/*
46+
* Copyright (c) 2025, Salesforce, Inc.
47+
* SPDX-License-Identifier: Apache-2
48+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
49+
*/
50+
```
51+
52+
The header is enforced by eslint via `eslint-plugin-header`. The canonical definition is in `eslint.config.mjs` (root) as `copyrightHeader`.
53+
4054
## Setup/Packaging
4155

4256
- use `pnpm` over `npm` for package management

packages/b2c-cli/package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
"@oclif/plugin-plugins": "^5",
1616
"@oclif/plugin-version": "^2",
1717
"@salesforce/b2c-tooling-sdk": "workspace:*",
18-
"cliui": "^9.0.1"
18+
"cliui": "^9.0.1",
19+
"marked": "^15.0.0",
20+
"marked-terminal": "^7.3.0"
1921
},
2022
"bundleDependencies": [
2123
"@oclif/core",
@@ -25,7 +27,9 @@
2527
"@oclif/plugin-plugins",
2628
"@oclif/plugin-version",
2729
"@salesforce/b2c-tooling-sdk",
28-
"cliui"
30+
"cliui",
31+
"marked",
32+
"marked-terminal"
2933
],
3034
"devDependencies": {
3135
"@eslint/compat": "^1",
@@ -88,6 +92,9 @@
8892
"code": {
8993
"description": "Deploy and manage code versions on instances"
9094
},
95+
"docs": {
96+
"description": "Search and read Script API documentation"
97+
},
9198
"job": {
9299
"description": "Run jobs and import/export site archives"
93100
},
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* SPDX-License-Identifier: Apache-2
4+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
import {Args, Flags} from '@oclif/core';
7+
import {InstanceCommand} from '@salesforce/b2c-tooling-sdk/cli';
8+
import {downloadDocs, type DownloadDocsResult} from '@salesforce/b2c-tooling-sdk/operations/docs';
9+
import {t} from '../../i18n/index.js';
10+
11+
export default class DocsDownload extends InstanceCommand<typeof DocsDownload> {
12+
static args = {
13+
output: Args.string({
14+
description: 'Output directory for extracted documentation',
15+
required: true,
16+
}),
17+
};
18+
19+
static description = t(
20+
'commands.docs.download.description',
21+
'Download Script API documentation from a B2C Commerce instance',
22+
);
23+
24+
static enableJsonFlag = true;
25+
26+
static examples = [
27+
'<%= config.bin %> <%= command.id %> ./docs',
28+
'<%= config.bin %> <%= command.id %> ./docs --keep-archive',
29+
'<%= config.bin %> <%= command.id %> --server sandbox.demandware.net ./my-docs',
30+
];
31+
32+
static flags = {
33+
...InstanceCommand.baseFlags,
34+
'keep-archive': Flags.boolean({
35+
description: 'Keep the downloaded archive file',
36+
default: false,
37+
}),
38+
};
39+
40+
async run(): Promise<DownloadDocsResult> {
41+
this.requireServer();
42+
this.requireWebDavCredentials();
43+
44+
const outputDir = this.args.output;
45+
const keepArchive = this.flags['keep-archive'];
46+
47+
this.log(
48+
t('commands.docs.download.downloading', 'Downloading documentation from {{hostname}}...', {
49+
hostname: this.resolvedConfig.hostname,
50+
}),
51+
);
52+
53+
const result = await downloadDocs(this.instance, {
54+
outputDir,
55+
keepArchive,
56+
});
57+
58+
if (this.jsonEnabled()) {
59+
return result;
60+
}
61+
62+
this.log(
63+
t('commands.docs.download.success', 'Downloaded {{count}} documentation files to {{path}}', {
64+
count: result.fileCount,
65+
path: result.outputPath,
66+
}),
67+
);
68+
69+
if (result.archivePath) {
70+
this.log(
71+
t('commands.docs.download.archiveKept', 'Archive saved to: {{path}}', {
72+
path: result.archivePath,
73+
}),
74+
);
75+
}
76+
77+
return result;
78+
}
79+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* SPDX-License-Identifier: Apache-2
4+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
import {Args, Flags} from '@oclif/core';
7+
import {marked} from 'marked';
8+
// eslint-disable-next-line import/namespace -- marked-terminal CJS module causes parser issues
9+
import {markedTerminal} from 'marked-terminal';
10+
import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli';
11+
import {readDocByQuery, type DocEntry} from '@salesforce/b2c-tooling-sdk/operations/docs';
12+
import {t} from '../../i18n/index.js';
13+
14+
interface ReadDocsResult {
15+
entry: DocEntry;
16+
content: string;
17+
}
18+
19+
// Configure marked with terminal renderer
20+
marked.use(
21+
markedTerminal({
22+
width: 80,
23+
reflowText: true,
24+
tableOptions: {
25+
wordWrap: true,
26+
colWidths: [35, 45],
27+
},
28+
}),
29+
);
30+
31+
export default class DocsRead extends BaseCommand<typeof DocsRead> {
32+
static args = {
33+
query: Args.string({
34+
description: 'Search query for documentation (class name, module path, or partial match)',
35+
required: true,
36+
}),
37+
};
38+
39+
static description = t('commands.docs.read.description', 'Read Script API documentation for a class or module');
40+
41+
static enableJsonFlag = true;
42+
43+
static examples = [
44+
'<%= config.bin %> <%= command.id %> ProductMgr',
45+
'<%= config.bin %> <%= command.id %> dw.catalog.ProductMgr',
46+
'<%= config.bin %> <%= command.id %> "dw system Status"',
47+
'<%= config.bin %> <%= command.id %> ProductMgr --raw',
48+
'<%= config.bin %> <%= command.id %> ProductMgr --json',
49+
];
50+
51+
static flags = {
52+
...BaseCommand.baseFlags,
53+
raw: Flags.boolean({
54+
char: 'r',
55+
description: 'Output raw markdown without terminal formatting',
56+
default: false,
57+
}),
58+
};
59+
60+
async run(): Promise<ReadDocsResult> {
61+
const {query} = this.args;
62+
const {raw} = this.flags;
63+
64+
const result = readDocByQuery(query);
65+
66+
if (!result) {
67+
this.error(t('commands.docs.read.notFound', 'No documentation found matching: {{query}}', {query}), {
68+
suggestions: ['Try a broader search term', 'Use "b2c docs search <query>" to see available matches'],
69+
});
70+
}
71+
72+
if (this.jsonEnabled()) {
73+
return result;
74+
}
75+
76+
// Determine if we should render markdown for terminal
77+
const useRaw = raw || !process.stdout.isTTY;
78+
79+
if (useRaw) {
80+
process.stdout.write(result.content);
81+
} else {
82+
const rendered = marked.parse(result.content);
83+
process.stdout.write(rendered as string);
84+
}
85+
86+
return result;
87+
}
88+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2025, Salesforce, Inc.
3+
* SPDX-License-Identifier: Apache-2
4+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
import {Args, Flags} from '@oclif/core';
7+
import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli';
8+
import {readSchemaByQuery, listSchemas, type SchemaEntry} from '@salesforce/b2c-tooling-sdk/operations/docs';
9+
import {t} from '../../i18n/index.js';
10+
11+
interface SchemaResult {
12+
entry: SchemaEntry;
13+
content: string;
14+
}
15+
16+
interface ListResult {
17+
entries: SchemaEntry[];
18+
}
19+
20+
export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
21+
static args = {
22+
query: Args.string({
23+
description: 'Schema name or partial match (e.g., "catalog", "order")',
24+
required: false,
25+
}),
26+
};
27+
28+
static description = t('commands.docs.schema.description', 'Read an XSD schema file');
29+
30+
static enableJsonFlag = true;
31+
32+
static examples = [
33+
'<%= config.bin %> <%= command.id %> catalog',
34+
'<%= config.bin %> <%= command.id %> order',
35+
'<%= config.bin %> <%= command.id %> --list',
36+
'<%= config.bin %> <%= command.id %> catalog --json',
37+
];
38+
39+
static flags = {
40+
...BaseCommand.baseFlags,
41+
list: Flags.boolean({
42+
char: 'l',
43+
description: 'List all available schemas',
44+
default: false,
45+
}),
46+
};
47+
48+
async run(): Promise<ListResult | SchemaResult> {
49+
const {query} = this.args;
50+
const {list} = this.flags;
51+
52+
// List mode
53+
if (list) {
54+
const entries = listSchemas();
55+
56+
if (this.jsonEnabled()) {
57+
return {entries};
58+
}
59+
60+
this.log(t('commands.docs.schema.available', 'Available schemas:'));
61+
for (const entry of entries) {
62+
this.log(` ${entry.id}`);
63+
}
64+
this.log('');
65+
this.log(t('commands.docs.schema.count', '{{count}} schemas available', {count: entries.length}));
66+
67+
return {entries};
68+
}
69+
70+
// Read mode requires query
71+
if (!query) {
72+
this.error(t('commands.docs.schema.queryRequired', 'Schema name is required. Use --list to see all schemas.'));
73+
}
74+
75+
const result = readSchemaByQuery(query);
76+
77+
if (!result) {
78+
this.error(t('commands.docs.schema.notFound', 'No schema found matching: {{query}}', {query}), {
79+
suggestions: ['Try a broader search term', 'Use "b2c docs schema --list" to see available schemas'],
80+
});
81+
}
82+
83+
if (this.jsonEnabled()) {
84+
return result;
85+
}
86+
87+
// Output the schema content
88+
process.stdout.write(result.content);
89+
90+
return result;
91+
}
92+
}

0 commit comments

Comments
 (0)