Skip to content

Commit 603ba54

Browse files
committed
feat(API): [PF-3167] Wire tools and resources to doc-core API
Signed-off-by: Jeff Puzzo <jpuzzo@redhat.com>
1 parent a7861d1 commit 603ba54

23 files changed

+1180
-674
lines changed

src/__tests__/__snapshots__/options.defaults.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
exports[`options defaults should return specific properties: defaults 1`] = `
44
{
5+
"apiBaseUrl": "https://staging.patternfly.org",
56
"contextPath": "/",
67
"contextUrl": "file:///",
78
"docsPath": "/documentation",

src/__tests__/__snapshots__/tool.componentSchemas.test.ts.snap

Lines changed: 8 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,8 @@ exports[`componentSchemasTool, callback should parse parameters, default 1`] = `
1212
{
1313
"content": [
1414
{
15-
"text": "{
16-
"$schema": "https://json-schema.org/draft/2020-12/schema",
17-
"type": "object",
18-
"title": "Button Props",
19-
"description": "Props for the Button component",
20-
"properties": {
21-
"variant": {
22-
"type": "string",
23-
"enum": [
24-
"primary",
25-
"secondary"
26-
]
27-
},
28-
"size": {
29-
"type": "string",
30-
"enum": [
31-
"sm",
32-
"md",
33-
"lg"
34-
]
35-
},
36-
"children": {
37-
"type": "string",
38-
"description": "Content rendered inside the button"
39-
}
40-
},
41-
"required": [
42-
"children"
43-
],
44-
"additionalProperties": false
45-
}",
15+
"text": "| Prop | Type |
16+
|---|---|",
4617
"type": "text",
4718
},
4819
],
@@ -53,37 +24,8 @@ exports[`componentSchemasTool, callback should parse parameters, with lower case
5324
{
5425
"content": [
5526
{
56-
"text": "{
57-
"$schema": "https://json-schema.org/draft/2020-12/schema",
58-
"type": "object",
59-
"title": "Button Props",
60-
"description": "Props for the Button component",
61-
"properties": {
62-
"variant": {
63-
"type": "string",
64-
"enum": [
65-
"primary",
66-
"secondary"
67-
]
68-
},
69-
"size": {
70-
"type": "string",
71-
"enum": [
72-
"sm",
73-
"md",
74-
"lg"
75-
]
76-
},
77-
"children": {
78-
"type": "string",
79-
"description": "Content rendered inside the button"
80-
}
81-
},
82-
"required": [
83-
"children"
84-
],
85-
"additionalProperties": false
86-
}",
27+
"text": "| Prop | Type |
28+
|---|---|",
8729
"type": "text",
8830
},
8931
],
@@ -94,37 +36,8 @@ exports[`componentSchemasTool, callback should parse parameters, with trimmed co
9436
{
9537
"content": [
9638
{
97-
"text": "{
98-
"$schema": "https://json-schema.org/draft/2020-12/schema",
99-
"type": "object",
100-
"title": "Button Props",
101-
"description": "Props for the Button component",
102-
"properties": {
103-
"variant": {
104-
"type": "string",
105-
"enum": [
106-
"primary",
107-
"secondary"
108-
]
109-
},
110-
"size": {
111-
"type": "string",
112-
"enum": [
113-
"sm",
114-
"md",
115-
"lg"
116-
]
117-
},
118-
"children": {
119-
"type": "string",
120-
"description": "Content rendered inside the button"
121-
}
122-
},
123-
"required": [
124-
"children"
125-
],
126-
"additionalProperties": false
127-
}",
39+
"text": "| Prop | Type |
40+
|---|---|",
12841
"type": "text",
12942
},
13043
],
@@ -135,37 +48,8 @@ exports[`componentSchemasTool, callback should parse parameters, with upper case
13548
{
13649
"content": [
13750
{
138-
"text": "{
139-
"$schema": "https://json-schema.org/draft/2020-12/schema",
140-
"type": "object",
141-
"title": "Button Props",
142-
"description": "Props for the Button component",
143-
"properties": {
144-
"variant": {
145-
"type": "string",
146-
"enum": [
147-
"primary",
148-
"secondary"
149-
]
150-
},
151-
"size": {
152-
"type": "string",
153-
"enum": [
154-
"sm",
155-
"md",
156-
"lg"
157-
]
158-
},
159-
"children": {
160-
"type": "string",
161-
"description": "Content rendered inside the button"
162-
}
163-
},
164-
"required": [
165-
"children"
166-
],
167-
"additionalProperties": false
168-
}",
51+
"text": "| Prop | Type |
52+
|---|---|",
16953
"type": "text",
17054
},
17155
],

src/__tests__/__snapshots__/tool.searchPatternFlyDocs.test.ts.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ exports[`searchPatternFlyDocsTool should have a consistent return structure: str
1010

1111
exports[`searchPatternFlyDocsTool, callback should parse parameters, default: search 1`] = `"# Search results for "Button", 1 matches found:"`;
1212

13-
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "*" searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
13+
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "*" searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;
1414

15-
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "all" searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
15+
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "all" searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;
1616

17-
exports[`searchPatternFlyDocsTool, callback should parse parameters, with empty searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
17+
exports[`searchPatternFlyDocsTool, callback should parse parameters, with empty searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;
1818

1919
exports[`searchPatternFlyDocsTool, callback should parse parameters, with lower case componentName: search 1`] = `"# Search results for "button", 1 matches found:"`;
2020

2121
exports[`searchPatternFlyDocsTool, callback should parse parameters, with made up componentName: search 1`] = `"No PatternFly documentation found matching "lorem ipsum dolor sit amet""`;
2222

2323
exports[`searchPatternFlyDocsTool, callback should parse parameters, with multiple words: search 1`] = `"# Search results for "Button Card Table", 3 matches found:"`;
2424

25-
exports[`searchPatternFlyDocsTool, callback should parse parameters, with partial componentName: search 1`] = `"# Search results for "ton", 2 matches found:"`;
25+
exports[`searchPatternFlyDocsTool, callback should parse parameters, with partial componentName: search 1`] = `"# Search results for "ton", 1 matches found:"`;
2626

2727
exports[`searchPatternFlyDocsTool, callback should parse parameters, with trimmed componentName: search 1`] = `"# Search results for " Button ", 1 matches found:"`;
2828

src/__tests__/resource.patternFlyDocsIndex.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,39 @@ import { patternFlyDocsIndexResource } from '../resource.patternFlyDocsIndex';
22
import { getLocalDocs } from '../docs.local';
33
import { isPlainObject } from '../server.helpers';
44

5-
// Mock dependencies
65
jest.mock('../docs.local');
6+
jest.mock('../server.caching', () => ({
7+
memo: jest.fn(fn => fn)
8+
}));
9+
10+
jest.mock('../api.client', () => ({
11+
getComponentList: Object.assign(
12+
jest.fn(async () => ['Alert', 'Button', 'Card']),
13+
{ memo: jest.fn(async () => ['Alert', 'Button', 'Card']) }
14+
),
15+
getComponentInfo: Object.assign(
16+
jest.fn(async (name: string) => ({
17+
name,
18+
section: 'components',
19+
page: name.toLowerCase(),
20+
tabs: ['react'],
21+
hasProps: true,
22+
hasCss: false,
23+
exampleCount: 0
24+
})),
25+
{
26+
memo: jest.fn(async (name: string) => ({
27+
name,
28+
section: 'components',
29+
page: name.toLowerCase(),
30+
tabs: ['react'],
31+
hasProps: true,
32+
hasCss: false,
33+
exampleCount: 0
34+
}))
35+
}
36+
)
37+
}));
738

839
const mockGetLocalDocs = getLocalDocs as jest.MockedFunction<typeof getLocalDocs>;
940

@@ -43,5 +74,8 @@ describe('patternFlyDocsIndexResource, callback', () => {
4374
expect(result.contents).toBeDefined();
4475
expect(Object.keys(result.contents[0])).toEqual(['uri', 'mimeType', 'text']);
4576
expect(result.contents[0].text).toContain('[@patternfly/react-guidelines](./guidelines/README.md)');
77+
expect(result.contents[0].text).toContain('Alert');
78+
expect(result.contents[0].text).toContain('Button');
79+
expect(result.contents[0].text).toContain('Card');
4680
});
4781
});

src/__tests__/resource.patternFlyDocsTemplate.test.ts

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { McpError } from '@modelcontextprotocol/sdk/types.js';
22
import { patternFlyDocsTemplateResource } from '../resource.patternFlyDocsTemplate';
3-
import { processDocsFunction } from '../server.getResources';
3+
import { fetchComponentData } from '../api.fetcher';
44
import { searchComponents } from '../tool.searchPatternFlyDocs';
55
import { isPlainObject } from '../server.helpers';
66

7-
// Mock dependencies
8-
jest.mock('../server.getResources');
7+
jest.mock('../api.fetcher');
98
jest.mock('../tool.searchPatternFlyDocs');
109
jest.mock('../server.caching', () => ({
1110
memo: jest.fn(fn => fn)
@@ -14,7 +13,7 @@ jest.mock('../options.context', () => ({
1413
getOptions: jest.fn(() => ({}))
1514
}));
1615

17-
const mockProcessDocs = processDocsFunction as jest.MockedFunction<typeof processDocsFunction>;
16+
const mockFetchComponentData = fetchComponentData as jest.MockedFunction<typeof fetchComponentData>;
1817
const mockSearchComponents = searchComponents as jest.MockedFunction<typeof searchComponents>;
1918

2019
describe('patternFlyDocsTemplateResource', () => {
@@ -43,47 +42,29 @@ describe('patternFlyDocsTemplateResource, callback', () => {
4342
{
4443
description: 'default',
4544
name: 'Button',
46-
urls: ['components/button.md'],
47-
result: 'Button documentation content'
48-
},
49-
{
50-
description: 'with multiple matched URLs',
51-
name: 'Card',
52-
urls: ['components/card.md', 'components/card-examples.md'],
53-
result: 'Card documentation content'
45+
docs: '# Button documentation content'
5446
},
5547
{
5648
description: 'with trimmed name',
5749
name: ' Table ',
58-
urls: ['components/table.md'],
59-
result: 'Table documentation content'
50+
docs: '# Table documentation content'
6051
},
6152
{
6253
description: 'with lower case name',
6354
name: 'button',
64-
urls: ['components/button.md'],
65-
result: 'Button documentation content'
55+
docs: '# Button documentation content'
6656
}
67-
])('should parse parameters and return documentation, $description', async ({ name, urls, result: mockResult }) => {
68-
mockSearchComponents.mockReturnValue({
69-
isSearchWildCardAll: false,
70-
firstExactMatch: undefined,
71-
exactMatches: [{ urls } as any],
72-
searchResults: []
73-
});
74-
mockProcessDocs.mockResolvedValue([{ content: mockResult }] as any);
57+
])('should parse parameters and return documentation, $description', async ({ name, docs }) => {
58+
mockFetchComponentData.mockResolvedValue({ name: name.trim(), info: {} as any, docs });
7559

7660
const [_name, _uri, _config, callback] = patternFlyDocsTemplateResource();
7761
const uri = new URL('patternfly://docs/Button');
7862
const variables = { name };
7963
const result = await callback(uri, variables);
8064

81-
expect(mockSearchComponents).toHaveBeenCalledWith(name);
82-
expect(mockProcessDocs).toHaveBeenCalledWith(urls);
83-
8465
expect(result.contents).toBeDefined();
8566
expect(Object.keys(result.contents[0])).toEqual(['uri', 'mimeType', 'text']);
86-
expect(result.contents[0].text).toContain(mockResult);
67+
expect(result.contents[0].text).toContain(docs);
8768
});
8869

8970
it.each([
@@ -115,14 +96,14 @@ describe('patternFlyDocsTemplateResource, callback', () => {
11596
await expect(callback(uri, variables)).rejects.toThrow(error);
11697
});
11798

118-
it('should handle documentation loading errors', async () => {
119-
mockSearchComponents.mockReturnValue({
99+
it('should handle documentation not found errors', async () => {
100+
mockFetchComponentData.mockResolvedValue(undefined);
101+
mockSearchComponents.mockResolvedValue({
120102
isSearchWildCardAll: false,
121103
firstExactMatch: undefined,
122104
exactMatches: [],
123105
searchResults: []
124106
});
125-
mockProcessDocs.mockRejectedValue(new Error('File not found'));
126107

127108
const [_name, _uri, _config, handler] = patternFlyDocsTemplateResource();
128109
const uri = new URL('patternfly://docs/Button');

0 commit comments

Comments
 (0)