diff --git a/CLAUDE.md b/CLAUDE.md index 356f4f1..a2bf304 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,6 +48,28 @@ Restart Claude Code after configuration. "What does the User schema look like?" ``` +## Key Features + +### Broken $ref Fallback +When specs have broken `$ref` pointers, parser falls back to non-dereferenced mode: +```typescript +// In lib/parser.ts +try { + spec = await SwaggerParser.dereference(specPath); // Try first +} catch { + spec = await SwaggerParser.parse(specPath); // Fallback +} +``` + +### .NET Name Sanitization +Converts .NET-style schema names to valid TypeScript: +```typescript +// In tools/generate.ts - sanitizeName() +"Namespace.Type" → "Type" +"Generic`1[Inner]" → "Generic_Inner" +"Company.Api.V5.ViewModel" → "ViewModel" +``` + ## Project Structure ``` @@ -58,9 +80,9 @@ src/ │ ├── validate.ts # validateSpec() → error collection │ ├── query.ts # queryEndpoints() → filtering logic │ ├── schema.ts # getSchema() → schema lookup -│ └── generate.ts # generateTypes() → TS code generation +│ └── generate.ts # generateTypes() → TS code generation + sanitizeName() ├── lib/ # Shared utilities -│ ├── parser.ts # SwaggerParser.dereference() wrapper +│ ├── parser.ts # SwaggerParser wrapper (dereference with fallback) │ ├── validator.ts # SwaggerParser.validate() wrapper │ └── types.ts # TypeScript interfaces └── utils/ @@ -115,8 +137,14 @@ npm run dev # Run with tsx (hot reload) # List tools echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js -# Call a tool +# Local spec echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"test/fixtures/petstore.yaml"}}}' | node dist/index.js + +# Remote URL +echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json"}}}' | node dist/index.js + +# Enterprise API with broken refs +echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"https://projects.moravia.com/api/swagger/v5/swagger.json"}}}' | node dist/index.js ``` ## Adding New Tools diff --git a/README.md b/README.md index ce82045..048ccb7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ MCP (Model Context Protocol) server for parsing, validating, and querying OpenAP - **Inspect** component schemas with resolved references - **Generate** TypeScript interfaces from schemas - **Support** both local files and remote URLs +- **Handle** broken `$ref` pointers gracefully (fallback mode) +- **Sanitize** .NET-style schema names for valid TypeScript ## Installation @@ -66,6 +68,7 @@ Parse an OpenAPI/Swagger spec and return metadata. - Server URLs - Path count, operation count, schema count - Tags +- Warning if spec has broken `$refs` (parsed without dereferencing) **Example:** ``` @@ -167,6 +170,14 @@ Generate TypeScript interfaces from schemas. - Arrays and nested objects - allOf (intersection), oneOf/anyOf (union) - additionalProperties as Record + - .NET-style names sanitized to valid TypeScript identifiers + +**Name Sanitization:** +| Original | Sanitized | +|----------|-----------| +| `Namespace.SubNs.TypeName` | `TypeName` | +| `GenericType\`1[InnerType]` | `GenericType_InnerType` | +| `Company.Api.V5.UserViewModel` | `UserViewModel` | **Examples:** ``` @@ -191,6 +202,24 @@ Generate only User and Order types from api.yaml | Remote URL (HTTPS) | `https://example.com/openapi.json` | | Remote URL (HTTP) | `http://localhost:3000/api-docs` | +## Broken $ref Handling + +When a spec contains broken `$ref` pointers (e.g., typos in schema names), the parser: + +1. **Attempts** full dereferencing first +2. **Falls back** to parsing without dereferencing if refs are broken +3. **Warns** in output: "Spec has broken $refs. Parsed without dereferencing." + +This allows you to still extract metadata, query endpoints, and generate types from imperfect specs. + +## Tested With + +| API | Stats | Notes | +|-----|-------|-------| +| Petstore (Swagger) | 14 paths, 20 ops | Standard test spec | +| Petstore (OpenAPI 3) | 3 paths, 5 ops | Local fixture | +| Moravia Symfonie | 293 paths, 381 ops, 185 schemas | Enterprise .NET API with broken $refs | + ## Architecture ``` @@ -203,7 +232,7 @@ src/ │ ├── schema.ts # get-schema implementation │ └── generate.ts # generate-types implementation ├── lib/ -│ ├── parser.ts # SwaggerParser wrapper +│ ├── parser.ts # SwaggerParser wrapper (with fallback) │ ├── validator.ts # Validation logic │ └── types.ts # TypeScript type definitions └── utils/ @@ -244,6 +273,9 @@ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js # Parse a spec echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"test/fixtures/petstore.yaml"}}}' | node dist/index.js + +# Test with remote URL +echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"parse-spec","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json"}}}' | node dist/index.js ``` ## Example Output @@ -286,6 +318,26 @@ export interface Pet { export type PetStatus = 'available' | 'pending' | 'sold'; ``` +### generate-types (from .NET API) + +```typescript +/** Original: Microsoft.AspNetCore.OData.Results.SingleResult`1[...] */ +export interface SingleResult_JobCommentViewModel { + queryable?: JobCommentViewModel[]; +} + +/** Job view model */ +export interface JobViewModel { + /** The identifier. */ + id?: number; + /** The name. MaxLength(255) */ + name: string; + /** The project identifier. */ + projectId: number; + // ... +} +``` + ## License MIT