mcp-openapi-schema-explorer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +24 -0
- package/.github/dependabot.yml +13 -0
- package/.github/workflows/ci.yml +111 -0
- package/.husky/pre-commit +6 -0
- package/.prettierignore +3 -0
- package/.prettierrc.json +12 -0
- package/.releaserc.json +23 -0
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +67 -0
- package/Dockerfile +3 -0
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/src/config.d.ts +15 -0
- package/dist/src/config.js +19 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/handlers/component-detail-handler.d.ts +14 -0
- package/dist/src/handlers/component-detail-handler.js +87 -0
- package/dist/src/handlers/component-detail-handler.js.map +1 -0
- package/dist/src/handlers/component-map-handler.d.ts +14 -0
- package/dist/src/handlers/component-map-handler.js +63 -0
- package/dist/src/handlers/component-map-handler.js.map +1 -0
- package/dist/src/handlers/handler-utils.d.ts +69 -0
- package/dist/src/handlers/handler-utils.js +180 -0
- package/dist/src/handlers/handler-utils.js.map +1 -0
- package/dist/src/handlers/operation-handler.d.ts +14 -0
- package/dist/src/handlers/operation-handler.js +86 -0
- package/dist/src/handlers/operation-handler.js.map +1 -0
- package/dist/src/handlers/path-item-handler.d.ts +14 -0
- package/dist/src/handlers/path-item-handler.js +66 -0
- package/dist/src/handlers/path-item-handler.js.map +1 -0
- package/dist/src/handlers/top-level-field-handler.d.ts +14 -0
- package/dist/src/handlers/top-level-field-handler.js +72 -0
- package/dist/src/handlers/top-level-field-handler.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +177 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rendering/components.d.ts +67 -0
- package/dist/src/rendering/components.js +177 -0
- package/dist/src/rendering/components.js.map +1 -0
- package/dist/src/rendering/document.d.ts +36 -0
- package/dist/src/rendering/document.js +147 -0
- package/dist/src/rendering/document.js.map +1 -0
- package/dist/src/rendering/path-item.d.ts +45 -0
- package/dist/src/rendering/path-item.js +141 -0
- package/dist/src/rendering/path-item.js.map +1 -0
- package/dist/src/rendering/paths.d.ts +26 -0
- package/dist/src/rendering/paths.js +78 -0
- package/dist/src/rendering/paths.js.map +1 -0
- package/dist/src/rendering/types.d.ts +50 -0
- package/dist/src/rendering/types.js +12 -0
- package/dist/src/rendering/types.js.map +1 -0
- package/dist/src/rendering/utils.d.ts +31 -0
- package/dist/src/rendering/utils.js +79 -0
- package/dist/src/rendering/utils.js.map +1 -0
- package/dist/src/services/formatters.d.ts +36 -0
- package/dist/src/services/formatters.js +52 -0
- package/dist/src/services/formatters.js.map +1 -0
- package/dist/src/services/reference-transform.d.ts +27 -0
- package/dist/src/services/reference-transform.js +75 -0
- package/dist/src/services/reference-transform.js.map +1 -0
- package/dist/src/services/spec-loader.d.ts +27 -0
- package/dist/src/services/spec-loader.js +77 -0
- package/dist/src/services/spec-loader.js.map +1 -0
- package/dist/src/types.d.ts +11 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/uri-builder.d.ts +81 -0
- package/dist/src/utils/uri-builder.js +121 -0
- package/dist/src/utils/uri-builder.js.map +1 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +4 -0
- package/dist/src/version.js.map +1 -0
- package/eslint.config.js +88 -0
- package/jest.config.js +32 -0
- package/justfile +66 -0
- package/memory-bank/activeContext.md +139 -0
- package/memory-bank/productContext.md +39 -0
- package/memory-bank/progress.md +141 -0
- package/memory-bank/projectbrief.md +50 -0
- package/memory-bank/systemPatterns.md +224 -0
- package/memory-bank/techContext.md +131 -0
- package/package.json +76 -0
- package/scripts/generate-version.js +49 -0
- package/src/config.ts +33 -0
- package/src/handlers/component-detail-handler.ts +121 -0
- package/src/handlers/component-map-handler.ts +92 -0
- package/src/handlers/handler-utils.ts +230 -0
- package/src/handlers/operation-handler.ts +114 -0
- package/src/handlers/path-item-handler.ts +88 -0
- package/src/handlers/top-level-field-handler.ts +92 -0
- package/src/index.ts +222 -0
- package/src/rendering/components.ts +228 -0
- package/src/rendering/document.ts +167 -0
- package/src/rendering/path-item.ts +157 -0
- package/src/rendering/paths.ts +87 -0
- package/src/rendering/types.ts +63 -0
- package/src/rendering/utils.ts +107 -0
- package/src/services/formatters.ts +71 -0
- package/src/services/reference-transform.ts +105 -0
- package/src/services/spec-loader.ts +88 -0
- package/src/types.ts +17 -0
- package/src/utils/uri-builder.ts +134 -0
- package/src/version.ts +4 -0
- package/test/__tests__/e2e/format.test.ts +224 -0
- package/test/__tests__/e2e/resources.test.ts +369 -0
- package/test/__tests__/e2e/spec-loading.test.ts +172 -0
- package/test/__tests__/unit/config.test.ts +39 -0
- package/test/__tests__/unit/handlers/component-detail-handler.test.ts +241 -0
- package/test/__tests__/unit/handlers/component-map-handler.test.ts +187 -0
- package/test/__tests__/unit/handlers/handler-utils.test.ts +255 -0
- package/test/__tests__/unit/handlers/operation-handler.test.ts +202 -0
- package/test/__tests__/unit/handlers/path-item-handler.test.ts +153 -0
- package/test/__tests__/unit/handlers/top-level-field-handler.test.ts +182 -0
- package/test/__tests__/unit/rendering/components.test.ts +269 -0
- package/test/__tests__/unit/rendering/document.test.ts +172 -0
- package/test/__tests__/unit/rendering/path-item.test.ts +197 -0
- package/test/__tests__/unit/rendering/paths.test.ts +115 -0
- package/test/__tests__/unit/services/formatters.test.ts +109 -0
- package/test/__tests__/unit/services/reference-transform.test.ts +320 -0
- package/test/__tests__/unit/services/spec-loader.test.ts +214 -0
- package/test/__tests__/unit/utils/uri-builder.test.ts +103 -0
- package/test/fixtures/complex-endpoint.json +146 -0
- package/test/fixtures/empty-api.json +8 -0
- package/test/fixtures/multi-component-types.json +55 -0
- package/test/fixtures/paths-test.json +61 -0
- package/test/fixtures/sample-api.json +68 -0
- package/test/fixtures/sample-v2-api.json +39 -0
- package/test/setup.ts +32 -0
- package/test/utils/console-helpers.ts +48 -0
- package/test/utils/mcp-test-helpers.ts +66 -0
- package/test/utils/test-types.ts +54 -0
- package/tsconfig.json +25 -0
- package/tsconfig.test.json +5 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; // Import ResourceTemplate
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
// Import new handlers
|
|
6
|
+
import { TopLevelFieldHandler } from './handlers/top-level-field-handler.js';
|
|
7
|
+
import { PathItemHandler } from './handlers/path-item-handler.js';
|
|
8
|
+
import { OperationHandler } from './handlers/operation-handler.js';
|
|
9
|
+
import { ComponentMapHandler } from './handlers/component-map-handler.js';
|
|
10
|
+
import { ComponentDetailHandler } from './handlers/component-detail-handler.js';
|
|
11
|
+
import { OpenAPITransformer, ReferenceTransformService } from './services/reference-transform.js';
|
|
12
|
+
import { SpecLoaderService } from './services/spec-loader.js';
|
|
13
|
+
import { createFormatter } from './services/formatters.js';
|
|
14
|
+
import { encodeUriPathComponent } from './utils/uri-builder.js'; // Import specific function
|
|
15
|
+
import { isOpenAPIV3, getValidatedComponentMap } from './handlers/handler-utils.js'; // Import type guard and helper
|
|
16
|
+
import { VERSION } from './version.js'; // Import the generated version
|
|
17
|
+
async function main() {
|
|
18
|
+
try {
|
|
19
|
+
// Get spec path and options from command line arguments
|
|
20
|
+
const [, , specPath, ...args] = process.argv;
|
|
21
|
+
const options = {
|
|
22
|
+
outputFormat: args.includes('--output-format')
|
|
23
|
+
? args[args.indexOf('--output-format') + 1]
|
|
24
|
+
: undefined,
|
|
25
|
+
};
|
|
26
|
+
// Load configuration
|
|
27
|
+
const config = loadConfig(specPath, options);
|
|
28
|
+
// Initialize services
|
|
29
|
+
const referenceTransform = new ReferenceTransformService();
|
|
30
|
+
referenceTransform.registerTransformer('openapi', new OpenAPITransformer());
|
|
31
|
+
const specLoader = new SpecLoaderService(config.specPath, referenceTransform);
|
|
32
|
+
await specLoader.loadSpec();
|
|
33
|
+
// Get the loaded spec to extract the title
|
|
34
|
+
const spec = await specLoader.getSpec(); // Rename back to spec
|
|
35
|
+
// Get the transformed spec for use in completions
|
|
36
|
+
const transformedSpec = await specLoader.getTransformedSpec({
|
|
37
|
+
resourceType: 'schema', // Use a default context
|
|
38
|
+
format: 'openapi',
|
|
39
|
+
});
|
|
40
|
+
const defaultServerName = 'OpenAPI Schema Explorer';
|
|
41
|
+
// Use original spec for title
|
|
42
|
+
const serverName = spec.info?.title
|
|
43
|
+
? `Schema Explorer for ${spec.info.title}`
|
|
44
|
+
: defaultServerName;
|
|
45
|
+
// Create MCP server with dynamic name
|
|
46
|
+
const server = new McpServer({
|
|
47
|
+
name: serverName,
|
|
48
|
+
version: VERSION, // Use the imported version
|
|
49
|
+
});
|
|
50
|
+
// Set up formatter and new handlers
|
|
51
|
+
const formatter = createFormatter(config.outputFormat);
|
|
52
|
+
const topLevelFieldHandler = new TopLevelFieldHandler(specLoader, formatter);
|
|
53
|
+
const pathItemHandler = new PathItemHandler(specLoader, formatter);
|
|
54
|
+
const operationHandler = new OperationHandler(specLoader, formatter);
|
|
55
|
+
const componentMapHandler = new ComponentMapHandler(specLoader, formatter);
|
|
56
|
+
const componentDetailHandler = new ComponentDetailHandler(specLoader, formatter);
|
|
57
|
+
// Register new resources
|
|
58
|
+
// 1. openapi://{field}
|
|
59
|
+
const fieldTemplate = new ResourceTemplate('openapi://{field}', {
|
|
60
|
+
list: undefined, // List is handled by the handler logic based on field value
|
|
61
|
+
complete: {
|
|
62
|
+
field: () => Object.keys(transformedSpec), // Use transformedSpec
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
server.resource('openapi-field', // Unique ID for the resource registration
|
|
66
|
+
fieldTemplate, {
|
|
67
|
+
// MimeType varies (text/plain for lists, JSON/YAML for details) - SDK might handle this? Or maybe set a default? Let's omit for now.
|
|
68
|
+
description: 'Access top-level fields (info, servers, tags), list paths, or list component types.',
|
|
69
|
+
name: 'OpenAPI Field/List', // Generic name
|
|
70
|
+
}, topLevelFieldHandler.handleRequest);
|
|
71
|
+
// 2. openapi://paths/{path}
|
|
72
|
+
const pathTemplate = new ResourceTemplate('openapi://paths/{path}', {
|
|
73
|
+
list: undefined, // List is handled by the handler
|
|
74
|
+
complete: {
|
|
75
|
+
path: () => Object.keys(transformedSpec.paths ?? {}).map(encodeUriPathComponent), // Use imported function directly
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
server.resource('openapi-path-methods', pathTemplate, {
|
|
79
|
+
mimeType: 'text/plain', // This always returns a list
|
|
80
|
+
description: 'List available HTTP methods for a specific path. (Note: {path} must be URL-encoded, e.g., /users/{id} becomes users%2F%7Bid%7D)',
|
|
81
|
+
name: 'Path Methods List',
|
|
82
|
+
}, pathItemHandler.handleRequest);
|
|
83
|
+
// 3. openapi://paths/{path}/{method*}
|
|
84
|
+
const operationTemplate = new ResourceTemplate('openapi://paths/{path}/{method*}', {
|
|
85
|
+
list: undefined, // Detail view handled by handler
|
|
86
|
+
complete: {
|
|
87
|
+
path: () => Object.keys(transformedSpec.paths ?? {}).map(encodeUriPathComponent), // Use imported function directly
|
|
88
|
+
method: () => [
|
|
89
|
+
// Provide static list of common methods
|
|
90
|
+
'GET',
|
|
91
|
+
'POST',
|
|
92
|
+
'PUT',
|
|
93
|
+
'DELETE',
|
|
94
|
+
'PATCH',
|
|
95
|
+
'OPTIONS',
|
|
96
|
+
'HEAD',
|
|
97
|
+
'TRACE',
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
server.resource('openapi-operation-detail', operationTemplate, {
|
|
102
|
+
mimeType: formatter.getMimeType(), // Detail view uses formatter
|
|
103
|
+
description: 'Get details for one or more specific API operations (methods). (Note: {path} must be URL-encoded, e.g., /users/{id} becomes users%2F%7Bid%7D)',
|
|
104
|
+
name: 'Operation Detail',
|
|
105
|
+
}, operationHandler.handleRequest);
|
|
106
|
+
// 4. openapi://components/{type}
|
|
107
|
+
const componentMapTemplate = new ResourceTemplate('openapi://components/{type}', {
|
|
108
|
+
list: undefined, // List is handled by the handler
|
|
109
|
+
complete: {
|
|
110
|
+
type: () => {
|
|
111
|
+
// Use type guard to ensure spec is V3 before accessing components
|
|
112
|
+
if (isOpenAPIV3(transformedSpec)) {
|
|
113
|
+
return Object.keys(transformedSpec.components ?? {});
|
|
114
|
+
}
|
|
115
|
+
return []; // Return empty array if not V3 (shouldn't happen ideally)
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
server.resource('openapi-component-list', componentMapTemplate, {
|
|
120
|
+
mimeType: 'text/plain', // This always returns a list
|
|
121
|
+
description: 'List available components of a specific type (e.g., schemas, parameters).',
|
|
122
|
+
name: 'Component List',
|
|
123
|
+
}, componentMapHandler.handleRequest);
|
|
124
|
+
// 5. openapi://components/{type}/{name*}
|
|
125
|
+
const componentDetailTemplate = new ResourceTemplate('openapi://components/{type}/{name*}', {
|
|
126
|
+
list: undefined, // Detail view handled by handler
|
|
127
|
+
complete: {
|
|
128
|
+
type: () => {
|
|
129
|
+
// Use type guard to ensure spec is V3 before accessing components
|
|
130
|
+
if (isOpenAPIV3(transformedSpec)) {
|
|
131
|
+
return Object.keys(transformedSpec.components ?? {});
|
|
132
|
+
}
|
|
133
|
+
return []; // Return empty array if not V3
|
|
134
|
+
}, // <<< Added missing closing brace
|
|
135
|
+
name: () => {
|
|
136
|
+
// Provide names only if there's exactly one component type defined
|
|
137
|
+
if (isOpenAPIV3(transformedSpec) &&
|
|
138
|
+
transformedSpec.components &&
|
|
139
|
+
Object.keys(transformedSpec.components).length === 1) {
|
|
140
|
+
// Get the single component type key (e.g., 'schemas')
|
|
141
|
+
const componentTypeKey = Object.keys(transformedSpec.components)[0];
|
|
142
|
+
// Use the helper to safely get the map
|
|
143
|
+
try {
|
|
144
|
+
const componentTypeMap = getValidatedComponentMap(transformedSpec, componentTypeKey);
|
|
145
|
+
return Object.keys(componentTypeMap);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
// Should not happen if key came from Object.keys, but handle defensively
|
|
149
|
+
console.error(`Error getting component map for key ${componentTypeKey}:`, error);
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Otherwise, return no completions for name
|
|
154
|
+
return [];
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
server.resource('openapi-component-detail', componentDetailTemplate, {
|
|
159
|
+
mimeType: formatter.getMimeType(), // Detail view uses formatter
|
|
160
|
+
description: 'Get details for one or more specific components (e.g., schemas, parameters).',
|
|
161
|
+
name: 'Component Detail',
|
|
162
|
+
}, componentDetailHandler.handleRequest);
|
|
163
|
+
// Start server
|
|
164
|
+
const transport = new StdioServerTransport();
|
|
165
|
+
await server.connect(transport);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error('Failed to start server:', error instanceof Error ? error.message : String(error));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Run the server
|
|
173
|
+
main().catch(error => {
|
|
174
|
+
console.error('Unhandled error:', error instanceof Error ? error.message : String(error));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
177
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import { RenderableSpecObject, RenderContext, RenderResultItem } from './types.js';
|
|
3
|
+
export type ComponentType = keyof OpenAPIV3.ComponentsObject;
|
|
4
|
+
export declare const VALID_COMPONENT_TYPES: ComponentType[];
|
|
5
|
+
/**
|
|
6
|
+
* Wraps an OpenAPIV3.ComponentsObject to make it renderable.
|
|
7
|
+
* Handles listing the available component types.
|
|
8
|
+
*/
|
|
9
|
+
export declare class RenderableComponents implements RenderableSpecObject {
|
|
10
|
+
private components;
|
|
11
|
+
constructor(components: OpenAPIV3.ComponentsObject | undefined);
|
|
12
|
+
/**
|
|
13
|
+
* Renders a list of available component types found in the spec.
|
|
14
|
+
* Corresponds to the `openapi://components` URI.
|
|
15
|
+
*/
|
|
16
|
+
renderList(context: RenderContext): RenderResultItem[];
|
|
17
|
+
/**
|
|
18
|
+
* Detail view for the main 'components' object isn't meaningful.
|
|
19
|
+
*/
|
|
20
|
+
renderDetail(context: RenderContext): RenderResultItem[];
|
|
21
|
+
/**
|
|
22
|
+
* Gets the map object for a specific component type.
|
|
23
|
+
* @param type - The component type (e.g., 'schemas').
|
|
24
|
+
* @returns The map (e.g., ComponentsObject['schemas']) or undefined.
|
|
25
|
+
*/
|
|
26
|
+
getComponentMap(type: ComponentType): Record<string, OpenAPIV3.SchemaObject | OpenAPIV3.ResponseObject | OpenAPIV3.ParameterObject | OpenAPIV3.ExampleObject | OpenAPIV3.RequestBodyObject | OpenAPIV3.HeaderObject | OpenAPIV3.SecuritySchemeObject | OpenAPIV3.LinkObject | OpenAPIV3.CallbackObject | OpenAPIV3.ReferenceObject> | undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a map of components of a specific type (e.g., all schemas).
|
|
30
|
+
* Handles listing component names and rendering component details.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RenderableComponentMap implements RenderableSpecObject {
|
|
33
|
+
private componentMap;
|
|
34
|
+
private componentType;
|
|
35
|
+
private mapUriSuffix;
|
|
36
|
+
constructor(componentMap: ReturnType<RenderableComponents['getComponentMap']>, componentType: ComponentType, // e.g., 'schemas'
|
|
37
|
+
mapUriSuffix: string);
|
|
38
|
+
/**
|
|
39
|
+
* Renders a list of component names for the specific type.
|
|
40
|
+
* Corresponds to the `openapi://components/{type}` URI.
|
|
41
|
+
*/
|
|
42
|
+
renderList(context: RenderContext): RenderResultItem[];
|
|
43
|
+
/**
|
|
44
|
+
* Renders the detail view for one or more specific named components
|
|
45
|
+
* Renders the detail view. For a component map, this usually means listing
|
|
46
|
+
* the component names, similar to renderList. The handler should call
|
|
47
|
+
* `renderComponentDetail` for specific component details.
|
|
48
|
+
*/
|
|
49
|
+
renderDetail(context: RenderContext): RenderResultItem[];
|
|
50
|
+
/**
|
|
51
|
+
* Renders the detail view for one or more specific named components
|
|
52
|
+
* within this map.
|
|
53
|
+
* Corresponds to the `openapi://components/{type}/{name*}` URI.
|
|
54
|
+
* This is called by the handler after identifying the name(s).
|
|
55
|
+
*
|
|
56
|
+
* @param _context - The rendering context (might be needed later).
|
|
57
|
+
* @param names - Array of component names.
|
|
58
|
+
* @returns An array of RenderResultItem representing the component details.
|
|
59
|
+
*/
|
|
60
|
+
renderComponentDetail(_context: RenderContext, names: string[]): RenderResultItem[];
|
|
61
|
+
/**
|
|
62
|
+
* Gets a specific component object by name.
|
|
63
|
+
* @param name - The name of the component.
|
|
64
|
+
* @returns The component object (or ReferenceObject) or undefined.
|
|
65
|
+
*/
|
|
66
|
+
getComponent(name: string): OpenAPIV3.SchemaObject | OpenAPIV3.ResponseObject | OpenAPIV3.ParameterObject | OpenAPIV3.ExampleObject | OpenAPIV3.RequestBodyObject | OpenAPIV3.HeaderObject | OpenAPIV3.SecuritySchemeObject | OpenAPIV3.LinkObject | OpenAPIV3.CallbackObject | OpenAPIV3.ReferenceObject | undefined;
|
|
67
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { createErrorResult, generateListHint } from './utils.js'; // Add .js
|
|
2
|
+
export const VALID_COMPONENT_TYPES = [
|
|
3
|
+
'schemas',
|
|
4
|
+
'responses',
|
|
5
|
+
'parameters',
|
|
6
|
+
'examples',
|
|
7
|
+
'requestBodies',
|
|
8
|
+
'headers',
|
|
9
|
+
'securitySchemes',
|
|
10
|
+
'links',
|
|
11
|
+
'callbacks',
|
|
12
|
+
// 'pathItems' is technically allowed but we handle paths separately
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Wraps an OpenAPIV3.ComponentsObject to make it renderable.
|
|
16
|
+
* Handles listing the available component types.
|
|
17
|
+
*/
|
|
18
|
+
export class RenderableComponents {
|
|
19
|
+
constructor(components) {
|
|
20
|
+
this.components = components;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Renders a list of available component types found in the spec.
|
|
24
|
+
* Corresponds to the `openapi://components` URI.
|
|
25
|
+
*/
|
|
26
|
+
renderList(context) {
|
|
27
|
+
if (!this.components || Object.keys(this.components).length === 0) {
|
|
28
|
+
return createErrorResult('components', 'No components found in the specification.');
|
|
29
|
+
}
|
|
30
|
+
const availableTypes = Object.keys(this.components).filter((key) => VALID_COMPONENT_TYPES.includes(key));
|
|
31
|
+
if (availableTypes.length === 0) {
|
|
32
|
+
return createErrorResult('components', 'No valid component types found.');
|
|
33
|
+
}
|
|
34
|
+
let listText = 'Available Component Types:\n\n';
|
|
35
|
+
availableTypes.sort().forEach(type => {
|
|
36
|
+
listText += `- ${type}\n`;
|
|
37
|
+
});
|
|
38
|
+
// Use the new hint generator structure
|
|
39
|
+
listText += generateListHint(context, { itemType: 'componentType' });
|
|
40
|
+
return [
|
|
41
|
+
{
|
|
42
|
+
uriSuffix: 'components',
|
|
43
|
+
data: listText,
|
|
44
|
+
renderAsList: true,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Detail view for the main 'components' object isn't meaningful.
|
|
50
|
+
*/
|
|
51
|
+
renderDetail(context) {
|
|
52
|
+
return this.renderList(context);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gets the map object for a specific component type.
|
|
56
|
+
* @param type - The component type (e.g., 'schemas').
|
|
57
|
+
* @returns The map (e.g., ComponentsObject['schemas']) or undefined.
|
|
58
|
+
*/
|
|
59
|
+
getComponentMap(type) {
|
|
60
|
+
// Use Map for safe access
|
|
61
|
+
if (!this.components) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const componentsMap = new Map(Object.entries(this.components));
|
|
65
|
+
// Cast needed as Map.get returns the value type or undefined
|
|
66
|
+
return componentsMap.get(type);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// =====================================================================
|
|
70
|
+
/**
|
|
71
|
+
* Wraps a map of components of a specific type (e.g., all schemas).
|
|
72
|
+
* Handles listing component names and rendering component details.
|
|
73
|
+
*/
|
|
74
|
+
export class RenderableComponentMap {
|
|
75
|
+
constructor(componentMap, componentType, // e.g., 'schemas'
|
|
76
|
+
mapUriSuffix // e.g., 'components/schemas'
|
|
77
|
+
) {
|
|
78
|
+
this.componentMap = componentMap;
|
|
79
|
+
this.componentType = componentType;
|
|
80
|
+
this.mapUriSuffix = mapUriSuffix;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Renders a list of component names for the specific type.
|
|
84
|
+
* Corresponds to the `openapi://components/{type}` URI.
|
|
85
|
+
*/
|
|
86
|
+
renderList(context) {
|
|
87
|
+
if (!this.componentMap || Object.keys(this.componentMap).length === 0) {
|
|
88
|
+
return createErrorResult(this.mapUriSuffix, `No components of type "${this.componentType}" found.`);
|
|
89
|
+
}
|
|
90
|
+
const names = Object.keys(this.componentMap).sort();
|
|
91
|
+
let listText = `Available ${this.componentType}:\n\n`;
|
|
92
|
+
names.forEach(name => {
|
|
93
|
+
listText += `- ${name}\n`;
|
|
94
|
+
});
|
|
95
|
+
// Use the new hint generator structure, providing parent type
|
|
96
|
+
listText += generateListHint(context, {
|
|
97
|
+
itemType: 'componentName',
|
|
98
|
+
parentComponentType: this.componentType,
|
|
99
|
+
});
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
uriSuffix: this.mapUriSuffix,
|
|
103
|
+
data: listText,
|
|
104
|
+
renderAsList: true,
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Renders the detail view for one or more specific named components
|
|
110
|
+
* Renders the detail view. For a component map, this usually means listing
|
|
111
|
+
* the component names, similar to renderList. The handler should call
|
|
112
|
+
* `renderComponentDetail` for specific component details.
|
|
113
|
+
*/
|
|
114
|
+
renderDetail(context) {
|
|
115
|
+
// Delegate to renderList as the primary view for a component map itself.
|
|
116
|
+
return this.renderList(context);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Renders the detail view for one or more specific named components
|
|
120
|
+
* within this map.
|
|
121
|
+
* Corresponds to the `openapi://components/{type}/{name*}` URI.
|
|
122
|
+
* This is called by the handler after identifying the name(s).
|
|
123
|
+
*
|
|
124
|
+
* @param _context - The rendering context (might be needed later).
|
|
125
|
+
* @param names - Array of component names.
|
|
126
|
+
* @returns An array of RenderResultItem representing the component details.
|
|
127
|
+
*/
|
|
128
|
+
renderComponentDetail(_context, names) {
|
|
129
|
+
if (!this.componentMap) {
|
|
130
|
+
// Create error results for all requested names if map is missing
|
|
131
|
+
return names.map(name => ({
|
|
132
|
+
uriSuffix: `${this.mapUriSuffix}/${name}`,
|
|
133
|
+
data: null,
|
|
134
|
+
isError: true,
|
|
135
|
+
errorText: `Component map for type "${this.componentType}" not found.`,
|
|
136
|
+
renderAsList: true,
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
const results = [];
|
|
140
|
+
for (const name of names) {
|
|
141
|
+
const component = this.getComponent(name);
|
|
142
|
+
const componentUriSuffix = `${this.mapUriSuffix}/${name}`;
|
|
143
|
+
if (!component) {
|
|
144
|
+
results.push({
|
|
145
|
+
uriSuffix: componentUriSuffix,
|
|
146
|
+
data: null,
|
|
147
|
+
isError: true,
|
|
148
|
+
errorText: `Component "${name}" of type "${this.componentType}" not found.`,
|
|
149
|
+
renderAsList: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Return the raw component object; handler will format it
|
|
154
|
+
results.push({
|
|
155
|
+
uriSuffix: componentUriSuffix,
|
|
156
|
+
data: component,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return results;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Gets a specific component object by name.
|
|
164
|
+
* @param name - The name of the component.
|
|
165
|
+
* @returns The component object (or ReferenceObject) or undefined.
|
|
166
|
+
*/
|
|
167
|
+
getComponent(name) {
|
|
168
|
+
// Use Map for safe access
|
|
169
|
+
if (!this.componentMap) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
const detailsMap = new Map(Object.entries(this.componentMap));
|
|
173
|
+
// No cast needed, Map.get returns the correct type (ValueType | undefined)
|
|
174
|
+
return detailsMap.get(name);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/rendering/components.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import { RenderableSpecObject, RenderContext, RenderResultItem } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wraps an OpenAPIV3.Document to make it renderable.
|
|
5
|
+
* Handles rendering for top-level fields like 'info', 'servers', etc.
|
|
6
|
+
* Delegates list rendering for 'paths' and 'components' to respective objects.
|
|
7
|
+
*/
|
|
8
|
+
export declare class RenderableDocument implements RenderableSpecObject {
|
|
9
|
+
private document;
|
|
10
|
+
constructor(document: OpenAPIV3.Document);
|
|
11
|
+
/**
|
|
12
|
+
* Renders a list view. For the document level, this is intended
|
|
13
|
+
* to be called only when the requested field is 'paths' or 'components'.
|
|
14
|
+
* The actual routing/delegation will happen in the handler based on the field.
|
|
15
|
+
*/
|
|
16
|
+
renderList(_context: RenderContext): RenderResultItem[];
|
|
17
|
+
/**
|
|
18
|
+
* Renders the detail view. For the document level, this should not be called
|
|
19
|
+
* directly without specifying a field. The handler should call
|
|
20
|
+
* `renderTopLevelFieldDetail` instead.
|
|
21
|
+
*/
|
|
22
|
+
renderDetail(_context: RenderContext): RenderResultItem[];
|
|
23
|
+
/**
|
|
24
|
+
* Renders the detail view for a *specific* top-level field (e.g., 'info', 'servers').
|
|
25
|
+
* This is called by the handler after identifying the field.
|
|
26
|
+
*
|
|
27
|
+
* @param context - The rendering context.
|
|
28
|
+
* @param fieldObject - The actual top-level field object to render (e.g., document.info).
|
|
29
|
+
* @param fieldName - The name of the field being rendered (e.g., 'info').
|
|
30
|
+
* @returns An array of RenderResultItem representing the detail view.
|
|
31
|
+
*/
|
|
32
|
+
renderTopLevelFieldDetail(context: RenderContext, fieldObject: unknown, fieldName: string): RenderResultItem[];
|
|
33
|
+
getPathsObject(): OpenAPIV3.PathsObject | undefined;
|
|
34
|
+
getComponentsObject(): OpenAPIV3.ComponentsObject | undefined;
|
|
35
|
+
getTopLevelField(fieldName: string): unknown;
|
|
36
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// No longer need ResourceContents here
|
|
2
|
+
// Placeholder for other renderable objects we'll create
|
|
3
|
+
// import { RenderablePaths } from './paths.js'; // Add .js
|
|
4
|
+
// import { RenderableComponents } from './components.js'; // Add .js
|
|
5
|
+
/**
|
|
6
|
+
* Wraps an OpenAPIV3.Document to make it renderable.
|
|
7
|
+
* Handles rendering for top-level fields like 'info', 'servers', etc.
|
|
8
|
+
* Delegates list rendering for 'paths' and 'components' to respective objects.
|
|
9
|
+
*/
|
|
10
|
+
export class RenderableDocument {
|
|
11
|
+
// TODO: Add RenderablePaths and RenderableComponents instances
|
|
12
|
+
// private renderablePaths: RenderablePaths;
|
|
13
|
+
// private renderableComponents: RenderableComponents;
|
|
14
|
+
constructor(document) {
|
|
15
|
+
this.document = document;
|
|
16
|
+
// Initialize renderable wrappers for paths and components here
|
|
17
|
+
// this.renderablePaths = new RenderablePaths(document.paths);
|
|
18
|
+
// this.renderableComponents = new RenderableComponents(document.components);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Renders a list view. For the document level, this is intended
|
|
22
|
+
* to be called only when the requested field is 'paths' or 'components'.
|
|
23
|
+
* The actual routing/delegation will happen in the handler based on the field.
|
|
24
|
+
*/
|
|
25
|
+
renderList(_context) {
|
|
26
|
+
// Prefix context with _
|
|
27
|
+
// This method should ideally not be called directly on the document
|
|
28
|
+
// without specifying 'paths' or 'components' as the field.
|
|
29
|
+
// The handler for openapi://{field} will delegate to the appropriate
|
|
30
|
+
// sub-object's renderList.
|
|
31
|
+
// Returning an error result item.
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
uriSuffix: 'error',
|
|
35
|
+
data: null, // No specific data for this error
|
|
36
|
+
isError: true,
|
|
37
|
+
errorText: 'Error: List rendering is only supported for specific fields like "paths" or "components" at the top level.',
|
|
38
|
+
renderAsList: true, // Errors often shown as plain text
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Renders the detail view. For the document level, this should not be called
|
|
44
|
+
* directly without specifying a field. The handler should call
|
|
45
|
+
* `renderTopLevelFieldDetail` instead.
|
|
46
|
+
*/
|
|
47
|
+
renderDetail(_context) {
|
|
48
|
+
// Prefix context with _
|
|
49
|
+
// This method implementation fulfills the interface requirement,
|
|
50
|
+
// but direct detail rendering of the whole document isn't meaningful here.
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
uriSuffix: 'error',
|
|
54
|
+
data: null,
|
|
55
|
+
isError: true,
|
|
56
|
+
errorText: 'Error: Detail rendering requires specifying a top-level field (e.g., "info", "servers").',
|
|
57
|
+
renderAsList: true, // Errors often shown as plain text
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Renders the detail view for a *specific* top-level field (e.g., 'info', 'servers').
|
|
63
|
+
* This is called by the handler after identifying the field.
|
|
64
|
+
*
|
|
65
|
+
* @param context - The rendering context.
|
|
66
|
+
* @param fieldObject - The actual top-level field object to render (e.g., document.info).
|
|
67
|
+
* @param fieldName - The name of the field being rendered (e.g., 'info').
|
|
68
|
+
* @returns An array of RenderResultItem representing the detail view.
|
|
69
|
+
*/
|
|
70
|
+
renderTopLevelFieldDetail(context, fieldObject, fieldName) {
|
|
71
|
+
// Ensure fieldObject is provided (handler should validate fieldName exists)
|
|
72
|
+
if (fieldObject === undefined || fieldObject === null) {
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
uriSuffix: fieldName,
|
|
76
|
+
data: null,
|
|
77
|
+
isError: true,
|
|
78
|
+
errorText: `Error: Field "${fieldName}" not found in the OpenAPI document.`,
|
|
79
|
+
renderAsList: true,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
// Avoid rendering structural fields that have dedicated list views
|
|
84
|
+
if (fieldName === 'paths' || fieldName === 'components') {
|
|
85
|
+
return [
|
|
86
|
+
{
|
|
87
|
+
uriSuffix: fieldName,
|
|
88
|
+
data: null,
|
|
89
|
+
isError: true,
|
|
90
|
+
errorText: `Error: Field "${fieldName}" should be accessed via its list view (${context.baseUri}${fieldName}). Use the list view first.`,
|
|
91
|
+
renderAsList: true,
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
// For successful detail rendering, return the data object itself.
|
|
97
|
+
// The handler will format it using the context.formatter.
|
|
98
|
+
return [
|
|
99
|
+
{
|
|
100
|
+
uriSuffix: fieldName,
|
|
101
|
+
data: fieldObject, // Pass the raw data
|
|
102
|
+
// isError defaults to false
|
|
103
|
+
// renderAsList defaults to false (meaning use detail formatter)
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Handle potential errors during data access or initial checks
|
|
109
|
+
// Formatting errors will be caught by the handler later
|
|
110
|
+
return [
|
|
111
|
+
{
|
|
112
|
+
uriSuffix: fieldName,
|
|
113
|
+
data: null,
|
|
114
|
+
isError: true,
|
|
115
|
+
errorText: `Error preparing field "${fieldName}" for rendering: ${error instanceof Error ? error.message : String(error)}`,
|
|
116
|
+
renderAsList: true,
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
} // End of renderTopLevelFieldDetail
|
|
121
|
+
// --- Helper methods to access specific parts ---
|
|
122
|
+
getPathsObject() {
|
|
123
|
+
return this.document.paths;
|
|
124
|
+
}
|
|
125
|
+
getComponentsObject() {
|
|
126
|
+
return this.document.components;
|
|
127
|
+
}
|
|
128
|
+
getTopLevelField(fieldName) {
|
|
129
|
+
// Define allowed top-level OpenAPI document properties
|
|
130
|
+
const allowedFields = [
|
|
131
|
+
'openapi',
|
|
132
|
+
'info',
|
|
133
|
+
'servers',
|
|
134
|
+
'paths',
|
|
135
|
+
'components',
|
|
136
|
+
'security',
|
|
137
|
+
'tags',
|
|
138
|
+
'externalDocs',
|
|
139
|
+
];
|
|
140
|
+
// Only allow access to documented OpenAPI properties
|
|
141
|
+
if (allowedFields.includes(fieldName)) {
|
|
142
|
+
return this.document[fieldName];
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
} // End of RenderableDocument class
|
|
147
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../../src/rendering/document.ts"],"names":[],"mappings":"AAEA,uCAAuC;AAEvC,wDAAwD;AACxD,2DAA2D;AAC3D,qEAAqE;AAErE;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IAC7B,+DAA+D;IAC/D,4CAA4C;IAC5C,sDAAsD;IAEtD,YAAoB,QAA4B;QAA5B,aAAQ,GAAR,QAAQ,CAAoB;QAC9C,+DAA+D;QAC/D,8DAA8D;QAC9D,6EAA6E;IAC/E,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,QAAuB;QAChC,wBAAwB;QACxB,oEAAoE;QACpE,2DAA2D;QAC3D,qEAAqE;QACrE,2BAA2B;QAC3B,kCAAkC;QAClC,OAAO;YACL;gBACE,SAAS,EAAE,OAAO;gBAClB,IAAI,EAAE,IAAI,EAAE,kCAAkC;gBAC9C,OAAO,EAAE,IAAI;gBACb,SAAS,EACP,4GAA4G;gBAC9G,YAAY,EAAE,IAAI,EAAE,mCAAmC;aACxD;SACF,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,QAAuB;QAClC,wBAAwB;QACxB,iEAAiE;QACjE,2EAA2E;QAC3E,OAAO;YACL;gBACE,SAAS,EAAE,OAAO;gBAClB,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,IAAI;gBACb,SAAS,EACP,0FAA0F;gBAC5F,YAAY,EAAE,IAAI,EAAE,mCAAmC;aACxD;SACF,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACH,yBAAyB,CACvB,OAAsB,EACtB,WAAoB,EACpB,SAAiB;QAEjB,4EAA4E;QAC5E,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACtD,OAAO;gBACL;oBACE,SAAS,EAAE,SAAS;oBACpB,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,iBAAiB,SAAS,sCAAsC;oBAC3E,YAAY,EAAE,IAAI;iBACnB;aACF,CAAC;QACJ,CAAC;QAED,mEAAmE;QACnE,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;YACxD,OAAO;gBACL;oBACE,SAAS,EAAE,SAAS;oBACpB,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,iBAAiB,SAAS,2CAA2C,OAAO,CAAC,OAAO,GAAG,SAAS,6BAA6B;oBACxI,YAAY,EAAE,IAAI;iBACnB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,kEAAkE;YAClE,0DAA0D;YAC1D,OAAO;gBACL;oBACE,SAAS,EAAE,SAAS;oBACpB,IAAI,EAAE,WAAW,EAAE,oBAAoB;oBACvC,4BAA4B;oBAC5B,gEAAgE;iBACjE;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,+DAA+D;YAC/D,wDAAwD;YACxD,OAAO;gBACL;oBACE,SAAS,EAAE,SAAS;oBACpB,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,0BAA0B,SAAS,oBAC5C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE;oBACF,YAAY,EAAE,IAAI;iBACnB;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,mCAAmC;IAErC,kDAAkD;IAElD,cAAc;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;IAClC,CAAC;IAED,gBAAgB,CAAC,SAAiB;QAChC,uDAAuD;QACvD,MAAM,aAAa,GAAoC;YACrD,SAAS;YACT,MAAM;YACN,SAAS;YACT,OAAO;YACP,YAAY;YACZ,UAAU;YACV,MAAM;YACN,cAAc;SACf,CAAC;QAEF,qDAAqD;QACrD,IAAI,aAAa,CAAC,QAAQ,CAAC,SAAqC,CAAC,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAqC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC,kCAAkC"}
|