Skip to content

Commit b30e427

Browse files
committed
xmllint support
1 parent 94b19d5 commit b30e427

5 files changed

Lines changed: 73 additions & 12 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@salesforce/b2c-cli': patch
3+
'@salesforce/b2c-tooling-sdk': patch
4+
---
5+
6+
Add `--path` flag to `b2c docs schema` to print the filesystem path to a schema file instead of its content, enabling use with tools like `xmllint` for XML validation.

docs/cli/docs.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,10 @@ b2c docs schema [query]
134134

135135
### Flags
136136

137-
| Flag | Description | Default |
138-
| -------------- | -------------------------- | ------- |
139-
| `--list`, `-l` | List all available schemas | `false` |
137+
| Flag | Description | Default |
138+
| -------------- | -------------------------------------------------------------- | ------- |
139+
| `--list`, `-l` | List all available schemas | `false` |
140+
| `--path`, `-p` | Print the filesystem path to the schema instead of its content | `false` |
140141

141142
### Examples
142143

@@ -152,11 +153,24 @@ b2c docs schema --list
152153

153154
# JSON output
154155
b2c docs schema catalog --json
156+
157+
# Get the filesystem path to a schema
158+
b2c docs schema catalog --path
155159
```
156160

157161
### Output
158162

159-
Without `--json`, the command writes schema XML directly to stdout. With `--list`, it prints available schema IDs and a total count.
163+
Without `--json`, the command writes schema XML directly to stdout. With `--path`, it prints the resolved filesystem path (useful for passing to XML validation tools). With `--list`, it prints available schema IDs and a total count.
164+
165+
### Validating XML with xmllint
166+
167+
Use the `--path` flag to pass schema paths directly to `xmllint` for XML validation:
168+
169+
```bash
170+
xmllint --schema "$(b2c docs schema catalog --path)" catalog.xml --noout
171+
```
172+
173+
This works because `--path` returns the real filesystem path, allowing `xmllint` to resolve relative schema imports (like `xml.xsd`) automatically.
160174

161175
---
162176

packages/b2c-cli/src/commands/docs/schema.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import {Args, Flags} from '@oclif/core';
6+
import {Args, Flags, ux} from '@oclif/core';
77
import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli';
88
import {readSchemaByQuery, listSchemas, type SchemaEntry} from '@salesforce/b2c-tooling-sdk/docs';
99
import {t} from '../../i18n/index.js';
1010

1111
interface SchemaResult {
1212
entry: SchemaEntry;
1313
content: string;
14+
path: string;
15+
}
16+
17+
interface PathResult {
18+
entry: SchemaEntry;
19+
path: string;
1420
}
1521

1622
interface ListResult {
@@ -34,6 +40,7 @@ export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
3440
'<%= config.bin %> <%= command.id %> order',
3541
'<%= config.bin %> <%= command.id %> --list',
3642
'<%= config.bin %> <%= command.id %> catalog --json',
43+
'xmllint --schema "$(<%= config.bin %> <%= command.id %> catalog --path)" file.xml --noout',
3744
];
3845

3946
static flags = {
@@ -43,16 +50,21 @@ export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
4350
description: 'List all available schemas',
4451
default: false,
4552
}),
53+
path: Flags.boolean({
54+
char: 'p',
55+
description: 'Print the filesystem path to the schema instead of its content',
56+
default: false,
57+
}),
4658
};
4759

4860
protected operations = {
4961
listSchemas,
5062
readSchemaByQuery,
5163
};
5264

53-
async run(): Promise<ListResult | SchemaResult> {
65+
async run(): Promise<ListResult | PathResult | SchemaResult> {
5466
const {query} = this.args;
55-
const {list} = this.flags;
67+
const {list, path: pathFlag} = this.flags;
5668

5769
// List mode
5870
if (list) {
@@ -85,6 +97,15 @@ export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
8597
});
8698
}
8799

100+
if (pathFlag) {
101+
if (this.jsonEnabled()) {
102+
return {entry: result.entry, path: result.path};
103+
}
104+
105+
ux.stdout(result.path);
106+
return {entry: result.entry, path: result.path};
107+
}
108+
88109
if (this.jsonEnabled()) {
89110
return result;
90111
}

packages/b2c-cli/test/commands/docs/schema.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
66

7+
import {ux} from '@oclif/core';
78
import {expect} from 'chai';
89
import {afterEach, beforeEach} from 'mocha';
910
import sinon from 'sinon';
@@ -51,7 +52,9 @@ describe('docs schema', () => {
5152
const command: any = await createCommand({}, {query: 'catalog'});
5253

5354
sinon.stub(command, 'jsonEnabled').returns(false);
54-
const readStub = sinon.stub().returns({entry: {id: 'catalog', title: 't', filePath: 'c.xsd'}, content: '<x/>'});
55+
const readStub = sinon
56+
.stub()
57+
.returns({entry: {id: 'catalog', title: 't', filePath: 'c.xsd'}, content: '<x/>', path: '/tmp/c.xsd'});
5558
command.operations = {...command.operations, readSchemaByQuery: readStub};
5659

5760
const writeStub = sinon.stub(process.stdout, 'write');
@@ -60,4 +63,21 @@ describe('docs schema', () => {
6063

6164
expect(writeStub.calledOnceWithExactly('<x/>')).to.equal(true);
6265
});
66+
67+
it('outputs filesystem path with --path flag', async () => {
68+
const command: any = await createCommand({path: true}, {query: 'catalog'});
69+
70+
sinon.stub(command, 'jsonEnabled').returns(false);
71+
const readStub = sinon
72+
.stub()
73+
.returns({entry: {id: 'catalog', title: 't', filePath: 'c.xsd'}, content: '<x/>', path: '/data/xsd/c.xsd'});
74+
command.operations = {...command.operations, readSchemaByQuery: readStub};
75+
76+
const stdoutStub = sinon.stub(ux, 'stdout');
77+
78+
const result = await command.run();
79+
80+
expect(stdoutStub.calledOnceWithExactly('/data/xsd/c.xsd')).to.equal(true);
81+
expect(result).to.deep.equal({entry: {id: 'catalog', title: 't', filePath: 'c.xsd'}, path: '/data/xsd/c.xsd'});
82+
});
6383
});

packages/b2c-tooling-sdk/src/docs/schema.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function listSchemas(): SchemaEntry[] {
5555
/**
5656
* Read a schema by its exact ID.
5757
*/
58-
export function readSchema(id: string): {entry: SchemaEntry; content: string} | null {
58+
export function readSchema(id: string): {entry: SchemaEntry; content: string; path: string} | null {
5959
const index = loadIndex();
6060
const entry = index.entries.find((e) => e.id === id);
6161

@@ -66,14 +66,14 @@ export function readSchema(id: string): {entry: SchemaEntry; content: string} |
6666
const filePath = path.join(XSD_DATA_DIR, entry.filePath);
6767
const content = fs.readFileSync(filePath, 'utf-8');
6868

69-
return {entry, content};
69+
return {entry, content, path: filePath};
7070
}
7171

7272
/**
7373
* Find a schema by fuzzy query and return its content.
7474
* Returns the best match or null if no match found.
7575
*/
76-
export function readSchemaByQuery(query: string): {entry: SchemaEntry; content: string} | null {
76+
export function readSchemaByQuery(query: string): {entry: SchemaEntry; content: string; path: string} | null {
7777
// First try exact match
7878
const exactMatch = readSchema(query);
7979
if (exactMatch) {
@@ -92,7 +92,7 @@ export function readSchemaByQuery(query: string): {entry: SchemaEntry; content:
9292
const filePath = path.join(XSD_DATA_DIR, bestMatch.item.filePath);
9393
const content = fs.readFileSync(filePath, 'utf-8');
9494

95-
return {entry: bestMatch.item, content};
95+
return {entry: bestMatch.item, content, path: filePath};
9696
}
9797

9898
/**

0 commit comments

Comments
 (0)