Repository: enzonotario/vitepress-openapi (ts)

Issue:
Cannot read properties of null (reading 'get')
### Current behavior

When calling the `getParsedSpec()` method of an `useOpenapi` instance, I get the following error:

```
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'get')
    at P8e (vitepress-openapi.es.js:68526:53)
    at r (vitepress-openapi.es.js:68540:18)
    at r (vitepress-openapi.es.js:68542:18)
    at r (vitepress-openapi.es.js:68537:18)
    at r (vitepress-openapi.es.js:68542:18)
    at r (vitepress-openapi.es.js:68542:18)
    at r (vitepress-openapi.es.js:68542:18)
    at r (vitepress-openapi.es.js:68542:18)
    at I8e (vitepress-openapi.es.js:68546:10)
    at Object.i [as getParsedSpec] (vitepress-openapi.es.js:68894:22)
```

### Desired behavior

_No response_

### Reproduction

_No response_

### Steps to reproduce

The open api json can be found here: https://api-docs.tacticaldefense.software/openapi.json

Minimal code to reproduce:

```
import { theme, useOpenapi } from 'vitepress-openapi'
import spec from 'openapi.json' assert { type: 'json' }

const openapi = useOpenapi({ spec })
openapi.getParsedSpec();
```

### Logs and Error Messages

_No response_

### Other Information

I noticed that `@trojs/openapi-dereference` is currently on v0.2.4, but your packages.json file includes 0.2.3... maybe as easy as upgrading the version?

Pull request:
fix(openapi parser): handle exceptions gracefully
<!-- Provide a general summary of your changes in the title above. -->

# Description

Gracefully handles OpenAPI parser exceptions.

Currently, it doesn't handle `anyOf` properly and fails to partialy parse the specification. If any part of the spec causes an error during parsing, the entire spec remains unparsed. However, it now handles exception gracefully and falls back to displaying the original unparsed schema.

- [VitePress OpenAPI](https://stackblitz.com/edit/enzonotario-vitepress-openapi-starter-qc6frc?file=public%2Fopenapi.json)
- [Sandbox Scalar](https://sandbox.scalar.com/e/3NDUS)

## Related issues/external references

Partially fixes #78 

## Types of changes

- Bug fix


Patch:
diff --git a/src/components/Schema/OASchemaTabs.vue b/src/components/Schema/OASchemaTabs.vue
index 8bba446..51b08bc 100644
--- a/src/components/Schema/OASchemaTabs.vue
+++ b/src/components/Schema/OASchemaTabs.vue
@@ -29,7 +29,7 @@ const themeConfig = useTheme()
 const useExample = ref(true)
 
 const schemaJson = computed(() => {
-  return generateSchemaJson(props.schema, useExample.value)
+  return generateSchemaJson(props.schema, useExample.value) ?? props.schema
 })
 
 const schemaHasExample = hasExample(props.schema)
diff --git a/src/lib/OpenApi.ts b/src/lib/OpenApi.ts
index c1013c8..c740e54 100644
--- a/src/lib/OpenApi.ts
+++ b/src/lib/OpenApi.ts
@@ -39,7 +39,13 @@ export function OpenApi({ spec }: { spec: any } = { spec: null }) {
 
   function getParsedSpec() {
     if (!parsedSpec) {
-      parsedSpec = dereferenceSync(merge(spec))
+      try {
+        const mergedSpec = merge(spec)
+        parsedSpec = dereferenceSync(mergedSpec)
+      } catch (error) {
+        console.warn('Failed to parse OpenAPI spec:', error)
+        parsedSpec = { ...spec }
+      }
     }
 
     return parsedSpec
diff --git a/src/lib/generateSchemaJson.ts b/src/lib/generateSchemaJson.ts
index f9869a7..48cd52b 100644
--- a/src/lib/generateSchemaJson.ts
+++ b/src/lib/generateSchemaJson.ts
@@ -7,6 +7,10 @@ export function generateSchemaJson(schema: any, useExample = false) {
 
   const properties = propertiesTypesJsonRecursive(schema, useExample, new Set())
 
+  if (properties === null) {
+    return null
+  }
+
   if (typeof properties === 'string' || typeof properties === 'number' || typeof properties === 'boolean') {
     return properties
   }


Test patch:
diff --git a/test/lib/generateSchemaJson.test.ts b/test/lib/generateSchemaJson.test.ts
index 2591aa1..54a7ce3 100644
--- a/test/lib/generateSchemaJson.test.ts
+++ b/test/lib/generateSchemaJson.test.ts
@@ -92,10 +92,10 @@ describe('generateSchemaJson', () => {
     expect(result).toBe(JSON.stringify({ name: 'string', age: 0, isActive: true }, null, 2))
   })
 
-  it('generates JSON for empty schema', () => {
+  it('returns null for empty schema', () => {
     const schema = {}
     const result = generateSchemaJson(schema)
-    expect(result).toBe(JSON.stringify({}, null, 2))
+    expect(result).toBe(null)
   })
 
   it('generates JSON for null schema', () => {