@scalar/workspace-store 0.3.1 → 0.3.2
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/CHANGELOG.md +8 -0
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/package.json +6 -2
- package/.turbo/turbo-build.log +0 -13
- package/esbuild.ts +0 -8
- package/src/client.test.ts +0 -409
- package/src/client.ts +0 -254
- package/src/helpers/general.ts +0 -30
- package/src/helpers/json-path-utils.test.ts +0 -13
- package/src/helpers/json-path-utils.ts +0 -38
- package/src/helpers/proxy.test.ts +0 -61
- package/src/helpers/proxy.ts +0 -213
- package/src/schemas/callback.ts +0 -13
- package/src/schemas/components.ts +0 -36
- package/src/schemas/contact.ts +0 -11
- package/src/schemas/discriminator.ts +0 -13
- package/src/schemas/encoding.ts +0 -17
- package/src/schemas/example.ts +0 -17
- package/src/schemas/external-documentation.ts +0 -9
- package/src/schemas/header.ts +0 -19
- package/src/schemas/info.ts +0 -23
- package/src/schemas/license.ts +0 -11
- package/src/schemas/link.ts +0 -24
- package/src/schemas/media-type.ts +0 -21
- package/src/schemas/oauth-flow.ts +0 -13
- package/src/schemas/oauthflows.ts +0 -16
- package/src/schemas/openapi-document.ts +0 -34
- package/src/schemas/operation-without-callback.ts +0 -37
- package/src/schemas/parameter.ts +0 -26
- package/src/schemas/path-item.ts +0 -35
- package/src/schemas/paths.ts +0 -11
- package/src/schemas/reference.ts +0 -20
- package/src/schemas/request-body.ts +0 -12
- package/src/schemas/response.ts +0 -16
- package/src/schemas/responses.ts +0 -14
- package/src/schemas/schema.ts +0 -26
- package/src/schemas/security-requirement.ts +0 -16
- package/src/schemas/security-scheme.ts +0 -58
- package/src/schemas/server-variable.ts +0 -11
- package/src/schemas/server-workspace.ts +0 -36
- package/src/schemas/server.ts +0 -12
- package/src/schemas/tag.ts +0 -12
- package/src/schemas/xml.ts +0 -19
- package/src/schemas.ts +0 -6
- package/src/server.test.ts +0 -470
- package/src/server.ts +0 -341
- package/test/helpers.ts +0 -16
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -8
- package/vite.config.ts +0 -9
package/CHANGELOG.md
CHANGED
package/dist/client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createMagicProxy } from "./helpers/proxy.js";
|
|
|
3
3
|
import { isObject } from "./helpers/general.js";
|
|
4
4
|
import { getValueByPath } from "./helpers/json-path-utils.js";
|
|
5
5
|
import { bundle } from "@scalar/openapi-parser";
|
|
6
|
-
import { fetchUrls } from "@scalar/openapi-parser/
|
|
6
|
+
import { fetchUrls } from "@scalar/openapi-parser/plugins-browser";
|
|
7
7
|
async function loadDocument(workspaceDocument) {
|
|
8
8
|
if ("url" in workspaceDocument) {
|
|
9
9
|
return fetchUrls().exec(workspaceDocument.url);
|
package/dist/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client.ts"],
|
|
4
|
-
"sourcesContent": ["import { reactive, toRaw } from 'vue'\nimport type { WorkspaceMeta, WorkspaceDocumentMeta, Workspace } from './schemas/server-workspace'\nimport { createMagicProxy } from './helpers/proxy'\nimport { isObject } from '@/helpers/general'\nimport { getValueByPath } from '@/helpers/json-path-utils'\nimport { bundle } from '@scalar/openapi-parser'\nimport { fetchUrls } from '@scalar/openapi-parser/
|
|
4
|
+
"sourcesContent": ["import { reactive, toRaw } from 'vue'\nimport type { WorkspaceMeta, WorkspaceDocumentMeta, Workspace } from './schemas/server-workspace'\nimport { createMagicProxy } from './helpers/proxy'\nimport { isObject } from '@/helpers/general'\nimport { getValueByPath } from '@/helpers/json-path-utils'\nimport { bundle } from '@scalar/openapi-parser'\nimport { fetchUrls } from '@scalar/openapi-parser/plugins-browser'\n\ntype WorkspaceDocumentMetaInput = { meta?: WorkspaceDocumentMeta; name: string }\ntype WorkspaceDocumentInput =\n | ({ document: Record<string, unknown> } & WorkspaceDocumentMetaInput)\n | ({ url: string } & WorkspaceDocumentMetaInput)\n\n/**\n * Resolves a workspace document from various input sources (URL, local file, or direct document object).\n *\n * @param workspaceDocument - The document input to resolve, which can be:\n * - A URL to fetch the document from\n * - A local file path to read the document from\n * - A direct document object\n * @returns A promise that resolves to an object containing:\n * - ok: boolean indicating if the resolution was successful\n * - data: The resolved document data\n *\n * @example\n * // Resolve from URL\n * const urlDoc = await loadDocument({ name: 'api', url: 'https://api.example.com/openapi.json' })\n *\n * // Resolve from local file\n * const fileDoc = await loadDocument({ name: 'local', path: './openapi.json' })\n *\n * // Resolve direct document\n * const directDoc = await loadDocument({\n * name: 'inline',\n * document: { openapi: '3.0.0', paths: {} }\n * })\n */\nasync function loadDocument(workspaceDocument: WorkspaceDocumentInput) {\n if ('url' in workspaceDocument) {\n return fetchUrls().exec(workspaceDocument.url)\n }\n\n return {\n ok: true as const,\n data: workspaceDocument.document,\n }\n}\n\n/**\n * Creates a reactive workspace store that manages documents and their metadata.\n * The store provides functionality for accessing, updating, and resolving document references.\n *\n * @param workspaceProps - Configuration object for the workspace\n * @param workspaceProps.meta - Optional metadata for the workspace\n * @param workspaceProps.documents - Optional record of documents to initialize the workspace with\n * @returns An object containing methods and getters for managing the workspace\n * @deprecated Use `createWorkspaceStore` instead.\n */\nexport function createWorkspaceStoreSync(workspaceProps?: {\n meta?: WorkspaceMeta\n}) {\n // Create a reactive workspace object with proxied documents\n // Each document is wrapped in a proxy to enable reactive updates and reference resolution\n const workspace = reactive({\n ...workspaceProps?.meta,\n documents: {},\n /**\n * Returns the currently active document from the workspace.\n * The active document is determined by the 'x-scalar-active-document' metadata field,\n * falling back to the first document in the workspace if no active document is specified.\n *\n * @returns The active document or undefined if no document is found\n */\n get activeDocument(): (typeof workspace.documents)[number] | undefined {\n const activeDocumentKey = workspace['x-scalar-active-document'] ?? Object.keys(workspace.documents)[0] ?? ''\n return workspace.documents[activeDocumentKey]\n },\n }) as Workspace\n\n // Cache to track visited nodes during reference resolution to prevent bundling the same subtree multiple times\n // This is needed because we are doing partial bundle operations\n const visitedNodesCache = new Set()\n\n return {\n /**\n * Returns the raw (non-reactive) workspace object\n */\n get rawWorkspace() {\n return toRaw(workspace)\n },\n /**\n * Returns the reactive workspace object with an additional activeDocument getter\n */\n get workspace() {\n return workspace\n },\n /**\n * Updates a specific metadata field in the workspace\n * @param key - The metadata field to update\n * @param value - The new value for the field\n * @example\n * // Update the workspace title\n * update('x-scalar-active-document', 'document-name')\n */\n update<K extends keyof WorkspaceMeta>(key: K, value: WorkspaceMeta[K]) {\n // @ts-ignore\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n throw new Error('Invalid key: cannot modify prototype')\n }\n Object.assign(workspace, { [key]: value })\n },\n /**\n * Updates a specific metadata field in a document\n * @param name - The name of the document to update ('active' or a specific document name)\n * @param key - The metadata field to update\n * @param value - The new value for the field\n * @throws Error if the specified document doesn't exist\n * @example\n * // Update the auth of the active document\n * updateDocument('active', 'x-scalar-active-auth', 'Bearer')\n * // Update the auth of a specific document\n * updateDocument('document-name', 'x-scalar-active-auth', 'Bearer')\n */\n updateDocument<K extends keyof WorkspaceDocumentMeta>(\n name: 'active' | (string & {}),\n key: K,\n value: WorkspaceDocumentMeta[K],\n ) {\n const currentDocument =\n workspace.documents[\n name === 'active'\n ? (workspace['x-scalar-active-document'] ?? Object.keys(workspace.documents)[0] ?? '')\n : name\n ]\n\n if (!currentDocument) {\n throw 'Please select a valid document'\n }\n\n Object.assign(currentDocument, { [key]: value })\n },\n /**\n * Resolves a reference in the active document by following the provided path and resolving any external $ref references.\n * This method traverses the document structure following the given path and resolves any $ref references it encounters.\n * During resolution, it sets a loading status and updates the reference with the resolved content.\n *\n * @param path - Array of strings representing the path to the reference (e.g. ['paths', '/users', 'get', 'responses', '200'])\n * @throws Error if the path is invalid or empty\n * @example\n * // Resolve a reference in the active document\n * resolve(['paths', '/users', 'get', 'responses', '200'])\n */\n resolve: async (path: string[]) => {\n const activeDocument = workspace.activeDocument\n\n const target = getValueByPath(activeDocument, path)\n\n if (!isObject(target)) {\n console.error(\n `Invalid path provided for resolution. Path: [${path.join(', ')}]. Found value of type: ${typeof target}. Expected an object.`,\n )\n return\n }\n\n // Bundle the target document with the active document as root, resolving any external references\n // and tracking resolution status through hooks\n return bundle(target, {\n root: activeDocument,\n treeShake: false,\n plugins: [fetchUrls()],\n urlMap: false,\n hooks: {\n onResolveStart: (node) => {\n node['$status'] = 'loading'\n },\n onResolveError: (node) => {\n node['$status'] = 'error'\n },\n },\n visitedNodes: visitedNodesCache,\n })\n },\n /**\n * Adds a new document to the workspace\n * @param document - The document content to add. This should be a valid OpenAPI/Swagger document or other supported format\n * @param meta - Metadata for the document, including its name and other properties defined in WorkspaceDocumentMeta\n * @example\n * // Add a new OpenAPI document to the workspace\n * store.addDocument({\n * name: 'name',\n * document: {\n * openapi: '3.0.0',\n * info: { title: 'title' },\n * },\n * meta: {\n * 'x-scalar-active-auth': 'Bearer',\n * 'x-scalar-active-server': 'production'\n * }\n * })\n */\n addDocument: async (input: WorkspaceDocumentInput) => {\n const { name, meta } = input\n\n const resolve = await loadDocument(input)\n\n if (!resolve.ok || !isObject(resolve.data)) {\n console.error(`Can not load the document '${name}'`)\n workspace.documents[name] = {\n ...meta,\n }\n return\n }\n\n workspace.documents[name] = createMagicProxy({ ...(resolve.data as Record<string, unknown>), ...meta })\n },\n }\n}\n\n/**\n * Creates a reactive workspace store that manages documents and their metadata.\n * The store provides functionality for accessing, updating, and resolving document references.\n *\n * @param workspaceProps - Configuration object for the workspace\n * @param workspaceProps.meta - Optional metadata for the workspace\n * @param workspaceProps.documents - Optional record of documents to initialize the workspace with\n * @returns An object containing methods and getters for managing the workspace\n * @example\n * // Create a workspace store with metadata and documents\n * const store = await createWorkspaceStore({\n * meta: {\n * name: 'My Workspace',\n * description: 'A workspace for my API'\n * },\n * documents: [\n * {\n * name: 'petstore',\n * document: {\n * openapi: '3.0.0',\n * info: { title: 'Petstore API' }\n * }\n * }\n * ]\n * })\n */\nexport async function createWorkspaceStore(workspaceProps?: {\n meta?: WorkspaceMeta\n documents?: WorkspaceDocumentInput[]\n}) {\n const store = createWorkspaceStoreSync({ meta: workspaceProps?.meta })\n\n await Promise.all(workspaceProps?.documents?.map((it) => store.addDocument(it)) ?? [])\n\n return store\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -16,10 +16,14 @@
|
|
|
16
16
|
"openapi",
|
|
17
17
|
"scalar"
|
|
18
18
|
],
|
|
19
|
-
"version": "0.3.
|
|
19
|
+
"version": "0.3.2",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=18"
|
|
22
22
|
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"CHANGELOG.md"
|
|
26
|
+
],
|
|
23
27
|
"type": "module",
|
|
24
28
|
"exports": {
|
|
25
29
|
"./client": {
|
|
@@ -41,7 +45,7 @@
|
|
|
41
45
|
"dependencies": {
|
|
42
46
|
"@sinclair/typebox": "0.34.3",
|
|
43
47
|
"vue": "^3.5.12",
|
|
44
|
-
"@scalar/openapi-parser": "0.
|
|
48
|
+
"@scalar/openapi-parser": "0.16.0",
|
|
45
49
|
"@scalar/openapi-types": "0.3.2"
|
|
46
50
|
},
|
|
47
51
|
"devDependencies": {
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @scalar/workspace-store@0.3.1 build /home/runner/work/scalar/scalar/packages/workspace-store
|
|
3
|
-
> scalar-build-esbuild
|
|
4
|
-
|
|
5
|
-
namespacePath . schemas
|
|
6
|
-
namespacePath . client
|
|
7
|
-
namespacePath . server
|
|
8
|
-
[32mUpdating package.json exports field…[0m
|
|
9
|
-
[34m@scalar/workspace-store: Build completed in 30.95ms[39m
|
|
10
|
-
|
|
11
|
-
> @scalar/workspace-store@0.3.1 types:build /home/runner/work/scalar/scalar/packages/workspace-store
|
|
12
|
-
> scalar-types-build
|
|
13
|
-
|
package/esbuild.ts
DELETED
package/src/client.test.ts
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
import { createServerWorkspaceStore } from '@/server'
|
|
2
|
-
import { createWorkspaceStore } from '@/client'
|
|
3
|
-
import { beforeEach, describe, expect, test } from 'vitest'
|
|
4
|
-
import fastify, { type FastifyInstance } from 'fastify'
|
|
5
|
-
import { afterEach } from 'node:test'
|
|
6
|
-
|
|
7
|
-
// Test document
|
|
8
|
-
const document = {
|
|
9
|
-
openapi: '3.0.0',
|
|
10
|
-
info: { title: 'My API' },
|
|
11
|
-
components: {
|
|
12
|
-
schemas: {
|
|
13
|
-
User: {
|
|
14
|
-
type: 'object',
|
|
15
|
-
properties: {
|
|
16
|
-
id: {
|
|
17
|
-
type: 'string',
|
|
18
|
-
description: 'The user ID',
|
|
19
|
-
},
|
|
20
|
-
name: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'The user name',
|
|
23
|
-
},
|
|
24
|
-
email: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
format: 'email',
|
|
27
|
-
description: 'The user email',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
paths: {
|
|
34
|
-
'/users': {
|
|
35
|
-
get: {
|
|
36
|
-
summary: 'Get all users',
|
|
37
|
-
responses: {
|
|
38
|
-
'200': {
|
|
39
|
-
description: 'Successful response',
|
|
40
|
-
content: {
|
|
41
|
-
'application/json': {
|
|
42
|
-
schema: {
|
|
43
|
-
type: 'array',
|
|
44
|
-
items: {
|
|
45
|
-
$ref: '#/components/schemas/User',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
describe('create-workspace-store', () => {
|
|
58
|
-
let server: FastifyInstance
|
|
59
|
-
|
|
60
|
-
beforeEach(() => {
|
|
61
|
-
server = fastify({ logger: false })
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
afterEach(async () => {
|
|
65
|
-
await server.close()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('should correctly update workspace metadata', async () => {
|
|
69
|
-
const store = await createWorkspaceStore({
|
|
70
|
-
meta: {
|
|
71
|
-
'x-scalar-theme': 'default',
|
|
72
|
-
'x-scalar-dark-mode': false,
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
store.update('x-scalar-dark-mode', true)
|
|
77
|
-
store.update('x-scalar-theme', 'saturn')
|
|
78
|
-
|
|
79
|
-
expect(store.rawWorkspace['x-scalar-dark-mode']).toBe(true)
|
|
80
|
-
expect(store.rawWorkspace['x-scalar-theme']).toBe('saturn')
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
test('should correctly update document metadata', async () => {
|
|
84
|
-
const store = await createWorkspaceStore({
|
|
85
|
-
documents: [
|
|
86
|
-
{
|
|
87
|
-
name: 'default',
|
|
88
|
-
document: {
|
|
89
|
-
openapi: '3.0.0',
|
|
90
|
-
info: { title: 'My API' },
|
|
91
|
-
},
|
|
92
|
-
meta: {
|
|
93
|
-
'x-scalar-active-auth': 'Bearer',
|
|
94
|
-
'x-scalar-active-server': 'server-1',
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
// Should update the active document
|
|
101
|
-
store.updateDocument('active', 'x-scalar-active-server', 'server-2')
|
|
102
|
-
store.updateDocument('active', 'x-scalar-active-auth', undefined)
|
|
103
|
-
expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe(undefined)
|
|
104
|
-
expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-2')
|
|
105
|
-
|
|
106
|
-
// Should update a specific document
|
|
107
|
-
store.updateDocument('default', 'x-scalar-active-server', 'server-3')
|
|
108
|
-
store.updateDocument('default', 'x-scalar-active-auth', 'Bearer')
|
|
109
|
-
expect(store.rawWorkspace.documents['default']['x-scalar-active-auth']).toBe('Bearer')
|
|
110
|
-
expect(store.rawWorkspace.documents['default']['x-scalar-active-server']).toBe('server-3')
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
test('should correctly get the correct document', async () => {
|
|
114
|
-
const store = await createWorkspaceStore({
|
|
115
|
-
documents: [
|
|
116
|
-
{
|
|
117
|
-
name: 'default',
|
|
118
|
-
document: {
|
|
119
|
-
openapi: '3.0.0',
|
|
120
|
-
info: { title: 'My API' },
|
|
121
|
-
},
|
|
122
|
-
meta: {
|
|
123
|
-
'x-scalar-active-auth': 'Bearer',
|
|
124
|
-
'x-scalar-active-server': 'server-1',
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: 'document2',
|
|
129
|
-
document: {
|
|
130
|
-
openapi: '3.0.0',
|
|
131
|
-
info: { title: 'Second API' },
|
|
132
|
-
},
|
|
133
|
-
meta: {
|
|
134
|
-
'x-scalar-active-auth': 'Bearer',
|
|
135
|
-
'x-scalar-active-server': 'server-1',
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
meta: {
|
|
140
|
-
'x-scalar-active-document': 'default',
|
|
141
|
-
},
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
// Correctly gets the active document
|
|
145
|
-
expect(store.workspace.activeDocument?.info?.title).toBe('My API')
|
|
146
|
-
|
|
147
|
-
store.update('x-scalar-active-document', 'document2')
|
|
148
|
-
expect(store.workspace.activeDocument?.info?.title).toBe('Second API')
|
|
149
|
-
|
|
150
|
-
// Correctly get a specific document
|
|
151
|
-
expect(store.workspace.documents['default'].info?.title).toBe('My API')
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
test('should correctly add new documents', async () => {
|
|
155
|
-
const store = await createWorkspaceStore({
|
|
156
|
-
documents: [],
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
await store.addDocument({
|
|
160
|
-
document: {
|
|
161
|
-
openapi: '3.0.0',
|
|
162
|
-
info: { title: 'My API' },
|
|
163
|
-
},
|
|
164
|
-
name: 'default',
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
store.update('x-scalar-active-document', 'default')
|
|
168
|
-
expect(store.workspace.activeDocument?.info?.title).toBe('My API')
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
test('should correctly resolve refs on the fly', async () => {
|
|
172
|
-
const store = await createWorkspaceStore({
|
|
173
|
-
documents: [
|
|
174
|
-
{
|
|
175
|
-
name: 'default',
|
|
176
|
-
document: {
|
|
177
|
-
openapi: '3.0.0',
|
|
178
|
-
info: { title: 'My API' },
|
|
179
|
-
components: {
|
|
180
|
-
schemas: {
|
|
181
|
-
User: {
|
|
182
|
-
type: 'object',
|
|
183
|
-
properties: {
|
|
184
|
-
id: {
|
|
185
|
-
type: 'string',
|
|
186
|
-
description: 'The user ID',
|
|
187
|
-
},
|
|
188
|
-
name: {
|
|
189
|
-
type: 'string',
|
|
190
|
-
description: 'The user name',
|
|
191
|
-
},
|
|
192
|
-
email: {
|
|
193
|
-
type: 'string',
|
|
194
|
-
format: 'email',
|
|
195
|
-
description: 'The user email',
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
paths: {
|
|
202
|
-
'/users': {
|
|
203
|
-
get: {
|
|
204
|
-
summary: 'Get all users',
|
|
205
|
-
responses: {
|
|
206
|
-
'200': {
|
|
207
|
-
description: 'Successful response',
|
|
208
|
-
content: {
|
|
209
|
-
'application/json': {
|
|
210
|
-
schema: {
|
|
211
|
-
type: 'array',
|
|
212
|
-
items: {
|
|
213
|
-
$ref: '#/components/schemas/User',
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
],
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
expect(
|
|
229
|
-
(store.workspace.activeDocument?.paths?.['/users'].get as any)?.responses?.[200].content['application/json']
|
|
230
|
-
.schema.items.properties.name,
|
|
231
|
-
).toEqual({
|
|
232
|
-
type: 'string',
|
|
233
|
-
description: 'The user name',
|
|
234
|
-
})
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
test('should correctly resolve chunks from the remote server', async () => {
|
|
238
|
-
server.get('/*', (req, res) => {
|
|
239
|
-
const path = req.url
|
|
240
|
-
const contents = serverStore.get(path)
|
|
241
|
-
|
|
242
|
-
res.send(contents)
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
const PORT = 9988
|
|
246
|
-
await server.listen({ port: PORT })
|
|
247
|
-
|
|
248
|
-
const serverStore = createServerWorkspaceStore({
|
|
249
|
-
mode: 'ssr',
|
|
250
|
-
baseUrl: `http://localhost:${PORT}`,
|
|
251
|
-
documents: [
|
|
252
|
-
{
|
|
253
|
-
name: 'default',
|
|
254
|
-
document,
|
|
255
|
-
},
|
|
256
|
-
],
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
const store = await createWorkspaceStore({
|
|
260
|
-
documents: [
|
|
261
|
-
{
|
|
262
|
-
name: 'default',
|
|
263
|
-
document: serverStore.getWorkspace().documents['default'],
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
// The operation should not be resolved on the fly
|
|
269
|
-
expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
|
|
270
|
-
'$ref': 'http://localhost:9988/default/operations/~1users/get#',
|
|
271
|
-
$global: true,
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
// We resolve the ref
|
|
275
|
-
await store.resolve(['paths', '/users', 'get'])
|
|
276
|
-
|
|
277
|
-
// We expect the ref to have been resolved with the correct contents
|
|
278
|
-
expect(store.workspace.activeDocument?.paths?.['/users'].get?.summary).toEqual(document.paths['/users'].get.summary)
|
|
279
|
-
|
|
280
|
-
expect(
|
|
281
|
-
(store.workspace.activeDocument?.paths?.['/users'].get as any).responses[200].content['application/json'].schema
|
|
282
|
-
.items,
|
|
283
|
-
).toEqual(document.components.schemas.User)
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
test('should load files form the remote url', async () => {
|
|
287
|
-
const PORT = 9989
|
|
288
|
-
const url = `http://localhost:${PORT}`
|
|
289
|
-
|
|
290
|
-
// Send the default document
|
|
291
|
-
server.get('/', (_, reply) => {
|
|
292
|
-
reply.send(document)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
await server.listen({ port: PORT })
|
|
296
|
-
|
|
297
|
-
const store = await createWorkspaceStore({
|
|
298
|
-
documents: [
|
|
299
|
-
{
|
|
300
|
-
url: url,
|
|
301
|
-
name: 'default',
|
|
302
|
-
},
|
|
303
|
-
],
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
expect(Object.keys(store.workspace.documents)).toEqual(['default'])
|
|
307
|
-
expect(store.workspace.documents['default'].info?.title).toEqual(document.info.title)
|
|
308
|
-
|
|
309
|
-
// Add a new remote file
|
|
310
|
-
await store.addDocument({ name: 'new', url: url })
|
|
311
|
-
|
|
312
|
-
expect(Object.keys(store.workspace.documents)).toEqual(['default', 'new'])
|
|
313
|
-
expect(store.workspace.documents['new'].info?.title).toEqual(document.info.title)
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
test('should handle circular references when we try to resolve all remote chunks recursively', async () => {
|
|
317
|
-
const document = {
|
|
318
|
-
openapi: '3.0.0',
|
|
319
|
-
info: { title: 'My API' },
|
|
320
|
-
components: {
|
|
321
|
-
schemas: {
|
|
322
|
-
User: {
|
|
323
|
-
type: 'object',
|
|
324
|
-
properties: {
|
|
325
|
-
id: {
|
|
326
|
-
type: 'string',
|
|
327
|
-
description: 'The user ID',
|
|
328
|
-
},
|
|
329
|
-
name: {
|
|
330
|
-
$ref: '#/components/schemas/Rec',
|
|
331
|
-
},
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
Rec: {
|
|
335
|
-
type: 'object',
|
|
336
|
-
properties: {
|
|
337
|
-
id: {
|
|
338
|
-
$ref: '#/components/schemas/User',
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
},
|
|
343
|
-
},
|
|
344
|
-
paths: {
|
|
345
|
-
'/users': {
|
|
346
|
-
get: {
|
|
347
|
-
summary: 'Get all users',
|
|
348
|
-
responses: {
|
|
349
|
-
'200': {
|
|
350
|
-
description: 'Successful response',
|
|
351
|
-
content: {
|
|
352
|
-
'application/json': {
|
|
353
|
-
schema: {
|
|
354
|
-
type: 'array',
|
|
355
|
-
items: {
|
|
356
|
-
$ref: '#/components/schemas/User',
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
},
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
server.get('/*', (req, res) => {
|
|
369
|
-
const path = req.url
|
|
370
|
-
const contents = serverStore.get(path)
|
|
371
|
-
|
|
372
|
-
res.send(contents)
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
const PORT = 6672
|
|
376
|
-
await server.listen({ port: PORT })
|
|
377
|
-
|
|
378
|
-
const serverStore = createServerWorkspaceStore({
|
|
379
|
-
mode: 'ssr',
|
|
380
|
-
baseUrl: `http://localhost:${PORT}`,
|
|
381
|
-
documents: [
|
|
382
|
-
{
|
|
383
|
-
name: 'default',
|
|
384
|
-
document,
|
|
385
|
-
},
|
|
386
|
-
],
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
const store = await createWorkspaceStore({
|
|
390
|
-
documents: [
|
|
391
|
-
{
|
|
392
|
-
name: 'default',
|
|
393
|
-
document: serverStore.getWorkspace().documents['default'],
|
|
394
|
-
},
|
|
395
|
-
],
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
// The operation should not be resolved on the fly
|
|
399
|
-
expect(store.workspace.activeDocument?.paths?.['/users'].get).toEqual({
|
|
400
|
-
'$ref': `http://localhost:${PORT}/default/operations/~1users/get#`,
|
|
401
|
-
$global: true,
|
|
402
|
-
})
|
|
403
|
-
|
|
404
|
-
// We resolve the ref
|
|
405
|
-
await store.resolve(['paths', '/users', 'get'])
|
|
406
|
-
|
|
407
|
-
expect((store.workspace.activeDocument?.components?.schemas?.['User'] as any)?.type).toBe('object')
|
|
408
|
-
})
|
|
409
|
-
})
|