@scalar/api-client 3.9.0 → 3.10.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/CHANGELOG.md +19 -0
- package/dist/plugins/posthog/sanitize-event-payload.d.ts.map +1 -1
- package/dist/plugins/posthog/sanitize-event-payload.js +2 -0
- package/dist/plugins/posthog/sanitize-event-payload.js.map +1 -1
- package/dist/style.css +10 -17
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts +7 -4
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +28 -15
- package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/find-client.d.ts +31 -31
- package/dist/v2/blocks/operation-code-sample/helpers/find-client.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/find-client.js +32 -39
- package/dist/v2/blocks/operation-code-sample/helpers/find-client.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/format-language.d.ts +8 -0
- package/dist/v2/blocks/operation-code-sample/helpers/format-language.d.ts.map +1 -0
- package/dist/v2/blocks/operation-code-sample/helpers/format-language.js +70 -0
- package/dist/v2/blocks/operation-code-sample/helpers/format-language.js.map +1 -0
- package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.d.ts +15 -5
- package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.js +23 -6
- package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.js +2 -2
- package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/get-clients.d.ts +2 -1
- package/dist/v2/blocks/operation-code-sample/helpers/get-clients.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/get-clients.js +23 -17
- package/dist/v2/blocks/operation-code-sample/helpers/get-clients.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.d.ts +38 -3
- package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.js +74 -8
- package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.js +12 -87
- package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.js.map +1 -1
- package/dist/v2/blocks/operation-code-sample/index.d.ts +1 -1
- package/dist/v2/blocks/operation-code-sample/index.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/index.js +2 -2
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +11 -6
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/workspace-events.d.ts.map +1 -1
- package/dist/v2/workspace-events.js +2 -0
- package/dist/v2/workspace-events.js.map +1 -1
- package/dist/vue-styles.css +7 -7
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @scalar/api-client
|
|
2
2
|
|
|
3
|
+
## 3.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#9398](https://github.com/scalar/scalar/pull/9398): feat: read code samples from x-readme, x-stainless and x-scalar extensions
|
|
8
|
+
|
|
9
|
+
In addition to `x-codeSamples`, the code sample picker now reads custom samples from `x-scalar-examples`, `x-stainless-snippets`, `x-stainless-examples`, and `x-readme.code-samples`. When more than one is present on an operation, the highest-priority source is used (x-scalar-examples > x-stainless-snippets > x-stainless-examples > x-readme > x-codeSamples).
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#9438](https://github.com/scalar/scalar/pull/9438): feat(api-reference): add an AsyncAPI server selector
|
|
14
|
+
|
|
15
|
+
Adds a server selector for AsyncAPI documents in the API reference introduction. It mirrors the OpenAPI server selector but works with the AsyncAPI server shape (a named map of `host`/`protocol`/`pathname`), labelling each server with its constructed connection URL.
|
|
16
|
+
|
|
17
|
+
Server selection and variable changes are now persisted to the workspace store via new `asyncapi-server:update:selected` and `asyncapi-server:update:variables` events and their mutators, mirroring the OpenAPI wiring.
|
|
18
|
+
|
|
19
|
+
- [#9404](https://github.com/scalar/scalar/pull/9404): Send `multipart/form-data` and `application/x-www-form-urlencoded` object properties using their OpenAPI encoding `style`/`explode` (for example `style: deepObject` produces `address[city]=...` bracket notation) instead of always JSON-stringifying them. The request sent over the wire now matches the generated code snippet.
|
|
20
|
+
- [#9408](https://github.com/scalar/scalar/pull/9408): Render the client library name as a plain label instead of a dropdown when only a single client is available
|
|
21
|
+
|
|
3
22
|
## 3.9.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-event-payload.d.ts","sourceRoot":"","sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAuBxE;;;;;;GAMG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,kBAAkB,GAAG,MAAM,kBAAkB,IAAI,CACrF,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEpD,4EAA4E;AAC5E,KAAK,gBAAgB,GAAG;KACrB,CAAC,IAAI,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS;CACjE,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"sanitize-event-payload.d.ts","sourceRoot":"","sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAuBxE;;;;;;GAMG;AACH,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,kBAAkB,GAAG,MAAM,kBAAkB,IAAI,CACrF,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAA;AAEpD,4EAA4E;AAC5E,KAAK,gBAAgB,GAAG;KACrB,CAAC,IAAI,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS;CACjE,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,gBAoI5B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,kBAAkB,EACrE,OAAO,CAAC,EACR,SAAS,kBAAkB,CAAC,CAAC,CAAC,KAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,GAAG,IAMpD,CAAA"}
|
|
@@ -98,6 +98,8 @@ var TRACKED_EVENTS = {
|
|
|
98
98
|
"server:update:variables": void 0,
|
|
99
99
|
"server:update:selected": void 0,
|
|
100
100
|
"server:clear:servers": void 0,
|
|
101
|
+
"asyncapi-server:update:selected": void 0,
|
|
102
|
+
"asyncapi-server:update:variables": void 0,
|
|
101
103
|
"tabs:update:tabs": void 0,
|
|
102
104
|
"tabs:close:tab": void 0,
|
|
103
105
|
"tabs:close:other-tabs": void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-event-payload.js","names":[],"sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"sourcesContent":["import { getValueAtPath } from '@scalar/helpers/object/get-value-at-path'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\n\n/**\n * Builds an extractor that pulls a string from `payload` at `path` and emits\n * it under `{ [key]: value }`. Returns `{}` when the leaf is missing or is\n * not a string.\n *\n * `key` defaults to the dotted form of `path` (e.g. `['meta', 'type']` becomes\n * `'meta.type'`), matching the existing PostHog property names.\n *\n * Built on `getValueAtPath`, so null/undefined traversal and missing segments\n * are handled centrally.\n */\nconst stringAtPath = (path: string[], key: string = path.join('.')) => {\n return (payload: unknown): Record<string, unknown> => {\n const value = getValueAtPath(payload, path)\n return typeof value === 'string' ? { [key]: value } : {}\n }\n}\n\n/** Extractor for events whose only useful property is the fact they fired. */\nconst empty = (): Record<string, unknown> => ({})\n\n/**\n * Allowlist of events that should be forwarded to PostHog.\n *\n * Each key is an event name; its value is an extractor that pulls only the\n * safe, non-PII properties we want to track. Events not in this map are\n * silently dropped — this keeps the analytics surface explicit and auditable.\n */\ntype PayloadExtractor<K extends keyof ApiReferenceEvents = keyof ApiReferenceEvents> = (\n payload: ApiReferenceEvents[K],\n) => Record<string, unknown> | ApiReferenceEvents[K]\n\n/** Maps every event to either a typed extractor or `undefined` (opt-out) */\ntype TrackedEventsMap = {\n [K in keyof ApiReferenceEvents]: PayloadExtractor<K> | undefined\n}\n\nexport const TRACKED_EVENTS: TrackedEventsMap = {\n // Auth events — track the scheme type so we know which auth methods are popular\n 'auth:update:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:active-index': stringAtPath(['meta', 'type']),\n 'auth:update:security-scheme': stringAtPath(['payload', 'type']),\n 'auth:clear:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:selected-scopes': stringAtPath(['meta', 'type']),\n 'auth:delete:security-scheme': empty,\n 'auth:clear:security-scheme-secrets': empty,\n 'auth:upsert:scopes': empty,\n 'auth:delete:scopes': empty,\n\n // Cookie events — track whether it belongs to a document or workspace\n 'cookie:upsert:cookie': stringAtPath(['collectionType']),\n 'cookie:delete:cookie': stringAtPath(['collectionType']),\n\n // Environment events — same document-vs-workspace distinction\n 'environment:upsert:environment': stringAtPath(['collectionType']),\n 'environment:delete:environment': stringAtPath(['collectionType']),\n 'environment:upsert:environment-variable': stringAtPath(['collectionType']),\n 'environment:delete:environment-variable': stringAtPath(['collectionType']),\n\n // Document lifecycle\n 'document:create:empty-document': empty,\n 'document:delete:document': empty,\n 'document:update:info': empty,\n 'document:update:icon': empty,\n 'document:update:watch-mode': empty,\n\n // Operation events — contentType helps us understand payload format usage\n 'operation:send:request:hotkey': empty,\n 'operation:cancel:request': empty,\n 'operation:create:operation': empty,\n 'operation:delete:operation': empty,\n 'operation:create:draft-example': empty,\n 'operation:delete:example': empty,\n 'operation:update:requestBody:contentType': stringAtPath(['payload', 'contentType']),\n 'operation:update:pathMethod': empty,\n 'operation:rename:example': empty,\n 'operation:reload:history': empty,\n\n // UI events — track which surfaces users interact with\n 'ui:open:client-modal': empty,\n 'ui:open:command-palette': empty,\n 'ui:open:settings': empty,\n 'ui:download:document': stringAtPath(['format']),\n 'ui:toggle:sidebar': empty,\n 'ui:save:local-document': empty,\n 'copy-url:address-bar': empty,\n 'tabs:add:tab': empty,\n 'tabs:copy:url': empty,\n\n // Server events\n 'server:add:server': empty,\n 'server:delete:server': empty,\n\n // Tag events\n 'tag:create:tag': empty,\n 'tag:delete:tag': empty,\n\n // Request lifecycle hooks — lets us measure request volume without capturing bodies\n 'hooks:on:request:sent': empty,\n 'hooks:on:request:complete': empty,\n 'hooks:on:rebase:document:complete': empty,\n\n // Workspace preference events\n 'workspace:update:color-mode': empty,\n 'workspace:update:theme': empty,\n 'workspace:update:selected-client': empty,\n 'workspace:update:active-proxy': (payload) => ({ enabled: !!payload }),\n 'workspace:update:active-environment': empty,\n\n // Meta events\n 'update:dark-mode': empty,\n 'update:active-document': empty,\n 'update:selected-client': empty,\n\n // Account funnel events\n 'log:login-click': empty,\n 'log:register-click': empty,\n 'log:user-login': empty,\n 'log:user-logout': empty,\n\n // Document sync and save events\n 'log:save-document': empty,\n 'log:sync-pull-document': empty,\n 'log:sync-push-document': empty,\n\n // ---------------------------------------------------------------------------\n // Do not track — explicitly opted out so new events cause a type error\n // until they are consciously placed above with a payload\n // ---------------------------------------------------------------------------\n 'auth:update:security-scheme-secrets': undefined,\n 'analytics:on:show-more': undefined,\n 'analytics:on:loaded': undefined,\n 'document:update:extension': undefined,\n 'operation:update:meta': undefined,\n 'operation:update:extension': undefined,\n 'operation:upsert:parameter': undefined,\n 'operation:update:extra-parameters': undefined,\n 'operation:delete:parameter': undefined,\n 'operation:delete-all:parameters': undefined,\n 'operation:update:requestBody:value': undefined,\n 'operation:update:requestBody:formValue': undefined,\n 'server:initialize:servers': undefined,\n 'server:update:server': undefined,\n 'server:update:variables': undefined,\n 'server:update:selected': undefined,\n 'server:clear:servers': undefined,\n 'tabs:update:tabs': undefined,\n 'tabs:close:tab': undefined,\n 'tabs:close:other-tabs': undefined,\n 'tabs:navigate:previous': undefined,\n 'tabs:navigate:next': undefined,\n 'tabs:focus:tab': undefined,\n 'tabs:focus:tab-last': undefined,\n 'ui:focus:address-bar': undefined,\n 'ui:focus:send-button': undefined,\n 'ui:focus:search': undefined,\n 'ui:open:create-workspace': undefined,\n 'ui:close:client-modal': undefined,\n 'ui:navigate': undefined,\n 'toggle:nav-item': undefined,\n 'select:nav-item': undefined,\n 'intersecting:nav-item': undefined,\n 'scroll-to:nav-item': undefined,\n 'scroll-to:model-by-name': undefined,\n 'copy-url:nav-item': undefined,\n 'tag:edit:tag': undefined,\n 'workspace:update:name': undefined,\n}\n\n/**\n * Returns sanitized properties for a tracked event, or `null` if the event\n * should not be captured at all.\n *\n * This is the only function that the PostHog plugin needs to call — it\n * encapsulates both the \"should we track this?\" decision and the \"what\n * properties are safe to send?\" extraction in one step.\n */\nexport const sanitizeEventPayload = <K extends keyof ApiReferenceEvents>(\n event: K,\n payload: ApiReferenceEvents[K],\n): Record<string, unknown> | ApiReferenceEvents[K] | null => {\n const extractor = TRACKED_EVENTS[event]\n if (!extractor) {\n return null\n }\n return extractor(payload)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sanitize-event-payload.js","names":[],"sources":["../../../src/plugins/posthog/sanitize-event-payload.ts"],"sourcesContent":["import { getValueAtPath } from '@scalar/helpers/object/get-value-at-path'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\n\n/**\n * Builds an extractor that pulls a string from `payload` at `path` and emits\n * it under `{ [key]: value }`. Returns `{}` when the leaf is missing or is\n * not a string.\n *\n * `key` defaults to the dotted form of `path` (e.g. `['meta', 'type']` becomes\n * `'meta.type'`), matching the existing PostHog property names.\n *\n * Built on `getValueAtPath`, so null/undefined traversal and missing segments\n * are handled centrally.\n */\nconst stringAtPath = (path: string[], key: string = path.join('.')) => {\n return (payload: unknown): Record<string, unknown> => {\n const value = getValueAtPath(payload, path)\n return typeof value === 'string' ? { [key]: value } : {}\n }\n}\n\n/** Extractor for events whose only useful property is the fact they fired. */\nconst empty = (): Record<string, unknown> => ({})\n\n/**\n * Allowlist of events that should be forwarded to PostHog.\n *\n * Each key is an event name; its value is an extractor that pulls only the\n * safe, non-PII properties we want to track. Events not in this map are\n * silently dropped — this keeps the analytics surface explicit and auditable.\n */\ntype PayloadExtractor<K extends keyof ApiReferenceEvents = keyof ApiReferenceEvents> = (\n payload: ApiReferenceEvents[K],\n) => Record<string, unknown> | ApiReferenceEvents[K]\n\n/** Maps every event to either a typed extractor or `undefined` (opt-out) */\ntype TrackedEventsMap = {\n [K in keyof ApiReferenceEvents]: PayloadExtractor<K> | undefined\n}\n\nexport const TRACKED_EVENTS: TrackedEventsMap = {\n // Auth events — track the scheme type so we know which auth methods are popular\n 'auth:update:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:active-index': stringAtPath(['meta', 'type']),\n 'auth:update:security-scheme': stringAtPath(['payload', 'type']),\n 'auth:clear:selected-security-schemes': stringAtPath(['meta', 'type']),\n 'auth:update:selected-scopes': stringAtPath(['meta', 'type']),\n 'auth:delete:security-scheme': empty,\n 'auth:clear:security-scheme-secrets': empty,\n 'auth:upsert:scopes': empty,\n 'auth:delete:scopes': empty,\n\n // Cookie events — track whether it belongs to a document or workspace\n 'cookie:upsert:cookie': stringAtPath(['collectionType']),\n 'cookie:delete:cookie': stringAtPath(['collectionType']),\n\n // Environment events — same document-vs-workspace distinction\n 'environment:upsert:environment': stringAtPath(['collectionType']),\n 'environment:delete:environment': stringAtPath(['collectionType']),\n 'environment:upsert:environment-variable': stringAtPath(['collectionType']),\n 'environment:delete:environment-variable': stringAtPath(['collectionType']),\n\n // Document lifecycle\n 'document:create:empty-document': empty,\n 'document:delete:document': empty,\n 'document:update:info': empty,\n 'document:update:icon': empty,\n 'document:update:watch-mode': empty,\n\n // Operation events — contentType helps us understand payload format usage\n 'operation:send:request:hotkey': empty,\n 'operation:cancel:request': empty,\n 'operation:create:operation': empty,\n 'operation:delete:operation': empty,\n 'operation:create:draft-example': empty,\n 'operation:delete:example': empty,\n 'operation:update:requestBody:contentType': stringAtPath(['payload', 'contentType']),\n 'operation:update:pathMethod': empty,\n 'operation:rename:example': empty,\n 'operation:reload:history': empty,\n\n // UI events — track which surfaces users interact with\n 'ui:open:client-modal': empty,\n 'ui:open:command-palette': empty,\n 'ui:open:settings': empty,\n 'ui:download:document': stringAtPath(['format']),\n 'ui:toggle:sidebar': empty,\n 'ui:save:local-document': empty,\n 'copy-url:address-bar': empty,\n 'tabs:add:tab': empty,\n 'tabs:copy:url': empty,\n\n // Server events\n 'server:add:server': empty,\n 'server:delete:server': empty,\n\n // Tag events\n 'tag:create:tag': empty,\n 'tag:delete:tag': empty,\n\n // Request lifecycle hooks — lets us measure request volume without capturing bodies\n 'hooks:on:request:sent': empty,\n 'hooks:on:request:complete': empty,\n 'hooks:on:rebase:document:complete': empty,\n\n // Workspace preference events\n 'workspace:update:color-mode': empty,\n 'workspace:update:theme': empty,\n 'workspace:update:selected-client': empty,\n 'workspace:update:active-proxy': (payload) => ({ enabled: !!payload }),\n 'workspace:update:active-environment': empty,\n\n // Meta events\n 'update:dark-mode': empty,\n 'update:active-document': empty,\n 'update:selected-client': empty,\n\n // Account funnel events\n 'log:login-click': empty,\n 'log:register-click': empty,\n 'log:user-login': empty,\n 'log:user-logout': empty,\n\n // Document sync and save events\n 'log:save-document': empty,\n 'log:sync-pull-document': empty,\n 'log:sync-push-document': empty,\n\n // ---------------------------------------------------------------------------\n // Do not track — explicitly opted out so new events cause a type error\n // until they are consciously placed above with a payload\n // ---------------------------------------------------------------------------\n 'auth:update:security-scheme-secrets': undefined,\n 'analytics:on:show-more': undefined,\n 'analytics:on:loaded': undefined,\n 'document:update:extension': undefined,\n 'operation:update:meta': undefined,\n 'operation:update:extension': undefined,\n 'operation:upsert:parameter': undefined,\n 'operation:update:extra-parameters': undefined,\n 'operation:delete:parameter': undefined,\n 'operation:delete-all:parameters': undefined,\n 'operation:update:requestBody:value': undefined,\n 'operation:update:requestBody:formValue': undefined,\n 'server:initialize:servers': undefined,\n 'server:update:server': undefined,\n 'server:update:variables': undefined,\n 'server:update:selected': undefined,\n 'server:clear:servers': undefined,\n 'asyncapi-server:update:selected': undefined,\n 'asyncapi-server:update:variables': undefined,\n 'tabs:update:tabs': undefined,\n 'tabs:close:tab': undefined,\n 'tabs:close:other-tabs': undefined,\n 'tabs:navigate:previous': undefined,\n 'tabs:navigate:next': undefined,\n 'tabs:focus:tab': undefined,\n 'tabs:focus:tab-last': undefined,\n 'ui:focus:address-bar': undefined,\n 'ui:focus:send-button': undefined,\n 'ui:focus:search': undefined,\n 'ui:open:create-workspace': undefined,\n 'ui:close:client-modal': undefined,\n 'ui:navigate': undefined,\n 'toggle:nav-item': undefined,\n 'select:nav-item': undefined,\n 'intersecting:nav-item': undefined,\n 'scroll-to:nav-item': undefined,\n 'scroll-to:model-by-name': undefined,\n 'copy-url:nav-item': undefined,\n 'tag:edit:tag': undefined,\n 'workspace:update:name': undefined,\n}\n\n/**\n * Returns sanitized properties for a tracked event, or `null` if the event\n * should not be captured at all.\n *\n * This is the only function that the PostHog plugin needs to call — it\n * encapsulates both the \"should we track this?\" decision and the \"what\n * properties are safe to send?\" extraction in one step.\n */\nexport const sanitizeEventPayload = <K extends keyof ApiReferenceEvents>(\n event: K,\n payload: ApiReferenceEvents[K],\n): Record<string, unknown> | ApiReferenceEvents[K] | null => {\n const extractor = TRACKED_EVENTS[event]\n if (!extractor) {\n return null\n }\n return extractor(payload)\n}\n"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -102,12 +102,9 @@
|
|
|
102
102
|
--scalar-radius: 3px;
|
|
103
103
|
--scalar-radius-lg: 6px;
|
|
104
104
|
--scalar-radius-xl: 8px;
|
|
105
|
-
--scalar-font: "Inter", -
|
|
106
|
-
"
|
|
107
|
-
--scalar-font-code: "JetBrains Mono", ui-monospace, Menlo, Monaco,
|
|
108
|
-
"Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono",
|
|
109
|
-
"Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono",
|
|
110
|
-
"Courier New", monospace;
|
|
105
|
+
--scalar-font: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
|
106
|
+
"Noto Color Emoji";
|
|
107
|
+
--scalar-font-code: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
111
108
|
--scalar-heading-1: 24px;
|
|
112
109
|
--scalar-page-description: 16px;
|
|
113
110
|
--scalar-heading-2: 20px;
|
|
@@ -2012,10 +2009,6 @@
|
|
|
2012
2009
|
top: 1lh;
|
|
2013
2010
|
}
|
|
2014
2011
|
|
|
2015
|
-
.scalar-app .top-\[calc\(10px\+0\.5lh\)\] {
|
|
2016
|
-
top: calc(10px + .5lh);
|
|
2017
|
-
}
|
|
2018
|
-
|
|
2019
2012
|
.scalar-app .top-\[calc\(100\%\+4px\)\] {
|
|
2020
2013
|
top: calc(100% + 4px);
|
|
2021
2014
|
}
|
|
@@ -6550,34 +6543,34 @@ to {
|
|
|
6550
6543
|
}
|
|
6551
6544
|
}
|
|
6552
6545
|
|
|
6553
|
-
.request-card[data-v-
|
|
6546
|
+
.request-card[data-v-70ede25b] {
|
|
6554
6547
|
color: var(--scalar-color-1);
|
|
6555
6548
|
font-size: var(--scalar-font-size-3);
|
|
6556
6549
|
}
|
|
6557
|
-
.request-method[data-v-
|
|
6550
|
+
.request-method[data-v-70ede25b] {
|
|
6558
6551
|
font-family: var(--scalar-font-code);
|
|
6559
6552
|
text-transform: uppercase;
|
|
6560
6553
|
margin-right: 6px;
|
|
6561
6554
|
}
|
|
6562
|
-
.request-card-footer[data-v-
|
|
6555
|
+
.request-card-footer[data-v-70ede25b] {
|
|
6563
6556
|
display: flex;
|
|
6564
6557
|
justify-content: flex-end;
|
|
6565
6558
|
padding: 6px;
|
|
6566
6559
|
flex-shrink: 0;
|
|
6567
6560
|
position: relative;
|
|
6568
6561
|
}
|
|
6569
|
-
.request-card-footer-addon[data-v-
|
|
6562
|
+
.request-card-footer-addon[data-v-70ede25b] {
|
|
6570
6563
|
display: flex;
|
|
6571
6564
|
align-items: center;
|
|
6572
6565
|
|
|
6573
6566
|
flex: 1;
|
|
6574
6567
|
min-width: 0;
|
|
6575
6568
|
}
|
|
6576
|
-
.request-editor-section[data-v-
|
|
6569
|
+
.request-editor-section[data-v-70ede25b] {
|
|
6577
6570
|
display: flex;
|
|
6578
6571
|
flex: 1;
|
|
6579
6572
|
}
|
|
6580
|
-
.request-card-simple[data-v-
|
|
6573
|
+
.request-card-simple[data-v-70ede25b] {
|
|
6581
6574
|
display: flex;
|
|
6582
6575
|
align-items: center;
|
|
6583
6576
|
justify-content: space-between;
|
|
@@ -6586,7 +6579,7 @@ to {
|
|
|
6586
6579
|
|
|
6587
6580
|
font-size: var(--scalar-small);
|
|
6588
6581
|
}
|
|
6589
|
-
.code-snippet[data-v-
|
|
6582
|
+
.code-snippet[data-v-70ede25b] {
|
|
6590
6583
|
display: flex;
|
|
6591
6584
|
flex-direction: column;
|
|
6592
6585
|
width: 100%;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods';
|
|
2
|
-
import { type AvailableClients } from '@scalar/snippetz';
|
|
3
2
|
import { type WorkspaceEventBus } from '@scalar/workspace-store/events';
|
|
4
3
|
import type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example';
|
|
5
4
|
import type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies';
|
|
@@ -16,11 +15,15 @@ export type OperationCodeSampleProps = {
|
|
|
16
15
|
*/
|
|
17
16
|
clientOptions: ClientOptionGroup[];
|
|
18
17
|
/**
|
|
19
|
-
* Pre-selected client, this will determine which client is initially selected in the dropdown
|
|
18
|
+
* Pre-selected client, this will determine which client is initially selected in the dropdown.
|
|
19
|
+
* Either a built-in client id (e.g. `js/fetch`) or a custom sample id (e.g. `custom/python`).
|
|
20
20
|
*
|
|
21
|
-
*
|
|
21
|
+
* Typed as a plain string: unioning the (large) client-id union with the `custom/...`
|
|
22
|
+
* ids overflows TypeScript's union-complexity limit inside this component's `defineProps`.
|
|
23
|
+
*
|
|
24
|
+
* @defaults to a custom sample if one is available, otherwise shell/curl
|
|
22
25
|
*/
|
|
23
|
-
selectedClient?:
|
|
26
|
+
selectedClient?: string;
|
|
24
27
|
/**
|
|
25
28
|
* Which server from the spec to use for the code example
|
|
26
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationCodeSample.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OperationCodeSample.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"names":[],"mappings":"AA2gBA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAErF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAEvE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAiBrE,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,yCAAyC,CAAA;AAMhD,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAA;IACpC;;OAEG;IACH,aAAa,EAAE,iBAAiB,EAAE,CAAA;IAClC;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;OAEG;IACH,cAAc,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IACpC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;OAEG;IACH,QAAQ,EAAE,iBAAiB,CAAA;IAC3B;;OAEG;IACH,eAAe,EAAE,0BAA0B,EAAE,CAAA;IAC7C;;OAEG;IACH,MAAM,EAAE,cAAc,CAAA;IACtB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,SAAS,EAAE,eAAe,CAAA;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,MAAM,CAAA;IAC5B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,EAAE,CAAA;IAC/B;;;OAGG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAA;AAED;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAyMlB,8DAA8D;sBAC1C,MAAM;;;;IAD1B,8DAA8D;sBAC1C,MAAM;;;;YArLhB,MAAM,OAAO;YACb,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO;EA6jB3D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_
|
|
|
2
2
|
import OperationCodeSample_vue_vue_type_script_setup_true_lang_default from "./OperationCodeSample.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue
|
|
5
|
-
var OperationCodeSample_default = /* @__PURE__ */ _plugin_vue_export_helper_default(OperationCodeSample_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var OperationCodeSample_default = /* @__PURE__ */ _plugin_vue_export_helper_default(OperationCodeSample_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-70ede25b"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { OperationCodeSample_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationCodeSample.vue.js","names":[],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport {\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n} from '@scalar/components/card'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarVirtualText } from '@scalar/components/virtual-text'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base p-2\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n color: var(--scalar-color-1);\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"OperationCodeSample.vue.js","names":[],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown.\n * Either a built-in client id (e.g. `js/fetch`) or a custom sample id (e.g. `custom/python`).\n *\n * Typed as a plain string: unioning the (large) client-id union with the `custom/...`\n * ids overflows TypeScript's union-complexity limit inside this component's `defineProps`.\n *\n * @defaults to a custom sample if one is available, otherwise shell/curl\n */\n selectedClient?: string\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport {\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n} from '@scalar/components/card'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarVirtualText } from '@scalar/components/virtual-text'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/** Total number of available clients across all option groups */\nconst clientCount = computed(() =>\n clients.value.reduce((total, group) => total + group.options.length, 0),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Sync the selection globally so other operations follow along. Custom samples\n // sync too (keyed by language), so picking e.g. the Python SDK example here\n // shows the Python example on every operation that ships one.\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clientCount\"\n #actions>\n <!-- Multiple clients: render a dropdown to switch between them -->\n <ScalarCombobox\n v-if=\"clientCount > 1\"\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n <!-- Single client: just show its label, no need for a dropdown -->\n <span\n v-else\n class=\"text-c-2 flex h-full w-fit items-center px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\">\n {{ localSelectedClient?.title }}\n </span>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base p-2\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n color: var(--scalar-color-1);\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":""}
|
|
@@ -3,8 +3,8 @@ import HttpMethod_default from "./HttpMethod.vue.js";
|
|
|
3
3
|
import { operationToHar } from "../helpers/operation-to-har/operation-to-har.js";
|
|
4
4
|
import { filterClientsByQuery } from "../helpers/filter-clients-by-query.js";
|
|
5
5
|
import { findClient } from "../helpers/find-client.js";
|
|
6
|
-
import { getClients } from "../helpers/get-clients.js";
|
|
7
6
|
import { getCustomCodeSamples } from "../helpers/get-custom-code-samples.js";
|
|
7
|
+
import { getClients } from "../helpers/get-clients.js";
|
|
8
8
|
import { getSecrets } from "../helpers/get-secrets.js";
|
|
9
9
|
import { generateCodeSnippet } from "../helpers/generate-code-snippet.js";
|
|
10
10
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeModels, onBeforeMount, openBlock, ref, renderSlot, toDisplayString, unref, useId, useModel, watch, withCtx } from "vue";
|
|
@@ -18,12 +18,17 @@ import { ScalarVirtualText } from "@scalar/components/virtual-text";
|
|
|
18
18
|
import { freezeElement } from "@scalar/helpers/dom/freeze-element";
|
|
19
19
|
//#region src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue?vue&type=script&setup=true&lang.ts
|
|
20
20
|
var _hoisted_1 = ["innerHTML"];
|
|
21
|
-
var _hoisted_2 =
|
|
22
|
-
|
|
21
|
+
var _hoisted_2 = {
|
|
22
|
+
key: 1,
|
|
23
|
+
class: "text-c-2 flex h-full w-fit items-center px-0.5 py-0 text-base font-normal",
|
|
24
|
+
"data-testid": "client-picker"
|
|
25
|
+
};
|
|
26
|
+
var _hoisted_3 = ["id"];
|
|
27
|
+
var _hoisted_4 = {
|
|
23
28
|
key: 0,
|
|
24
29
|
class: "request-card-footer-addon"
|
|
25
30
|
};
|
|
26
|
-
var
|
|
31
|
+
var _hoisted_5 = { class: "request-header" };
|
|
27
32
|
var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
28
33
|
__name: "OperationCodeSample",
|
|
29
34
|
props: /* @__PURE__ */ mergeModels({
|
|
@@ -68,11 +73,18 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
68
73
|
/** Grab any custom code samples from the operation */
|
|
69
74
|
const customCodeSamples = computed(() => getCustomCodeSamples(__props.operation));
|
|
70
75
|
/** Merge custom code samples with the client options */
|
|
71
|
-
const clients = computed(() => getClients(customCodeSamples.value, __props.clientOptions));
|
|
76
|
+
const clients = computed(() => getClients(customCodeSamples.value.samples, __props.clientOptions, customCodeSamples.value.label));
|
|
77
|
+
/** Total number of available clients across all option groups */
|
|
78
|
+
const clientCount = computed(() => clients.value.reduce((total, group) => total + group.options.length, 0));
|
|
72
79
|
/** The locally selected client which would include code samples from this operation only */
|
|
73
80
|
const localSelectedClient = ref(findClient(clients.value, __props.selectedClient));
|
|
74
|
-
/**
|
|
75
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Re-resolve the local client whenever the global selection or the available
|
|
83
|
+
* clients change. Watching `clients` matters when navigating between operations:
|
|
84
|
+
* the stored id stays the same, but the matching option (e.g. a custom sample)
|
|
85
|
+
* differs per operation, so without this the snippet could go stale.
|
|
86
|
+
*/
|
|
87
|
+
watch([() => __props.selectedClient, clients], ([newClient]) => {
|
|
76
88
|
const client = findClient(clients.value, newClient);
|
|
77
89
|
if (client) localSelectedClient.value = client;
|
|
78
90
|
});
|
|
@@ -100,7 +112,7 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
100
112
|
defaultDisabledParameters: false,
|
|
101
113
|
includeDefaultHeaders: __props.integration === "client",
|
|
102
114
|
clientId: localSelectedClient.value?.id,
|
|
103
|
-
customCodeSamples: customCodeSamples.value,
|
|
115
|
+
customCodeSamples: customCodeSamples.value.samples,
|
|
104
116
|
operation: __props.operation,
|
|
105
117
|
method: __props.method,
|
|
106
118
|
path: __props.path,
|
|
@@ -140,7 +152,7 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
140
152
|
}, 300);
|
|
141
153
|
}
|
|
142
154
|
localSelectedClient.value = option;
|
|
143
|
-
if (option
|
|
155
|
+
if (option) __props.eventBus.emit("workspace:update:selected-client", option.id);
|
|
144
156
|
};
|
|
145
157
|
const VIRTUALIZATION_THRESHOLD = 2e4;
|
|
146
158
|
const shouldVirtualize = computed(() => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD);
|
|
@@ -168,9 +180,10 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
168
180
|
renderSlot(_ctx.$slots, "header", {}, void 0, true)
|
|
169
181
|
]),
|
|
170
182
|
_: 2
|
|
171
|
-
}, [!__props.isWebhook &&
|
|
183
|
+
}, [!__props.isWebhook && clientCount.value ? {
|
|
172
184
|
name: "actions",
|
|
173
|
-
fn: withCtx(() => [
|
|
185
|
+
fn: withCtx(() => [clientCount.value > 1 ? (openBlock(), createBlock(unref(ScalarCombobox), {
|
|
186
|
+
key: 0,
|
|
174
187
|
class: "max-h-80",
|
|
175
188
|
filterFn: unref(filterClientsByQuery),
|
|
176
189
|
modelValue: localSelectedClient.value,
|
|
@@ -195,7 +208,7 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
195
208
|
"filterFn",
|
|
196
209
|
"modelValue",
|
|
197
210
|
"options"
|
|
198
|
-
])]),
|
|
211
|
+
])) : (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(localSelectedClient.value?.title), 1))]),
|
|
199
212
|
key: "0"
|
|
200
213
|
} : void 0]), 1024),
|
|
201
214
|
createVNode(unref(ScalarCardSection), { class: "request-editor-section custom-scroll p-0" }, {
|
|
@@ -219,14 +232,14 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
219
232
|
contentClass: "language-plaintext whitespace-pre font-code text-base p-2",
|
|
220
233
|
lineHeight: 20,
|
|
221
234
|
text: generatedCode.value
|
|
222
|
-
}, null, 8, ["text"]))], 8,
|
|
235
|
+
}, null, 8, ["text"]))], 8, _hoisted_3)]),
|
|
223
236
|
_: 1
|
|
224
237
|
}),
|
|
225
238
|
Object.keys(requestBodyExamples.value).length > 1 || _ctx.$slots.footer ? (openBlock(), createBlock(unref(ScalarCardFooter), {
|
|
226
239
|
key: 0,
|
|
227
240
|
class: "request-card-footer bg-b-3"
|
|
228
241
|
}, {
|
|
229
|
-
default: withCtx(() => [Object.keys(requestBodyExamples.value).length > 1 ? (openBlock(), createElementBlock("div",
|
|
242
|
+
default: withCtx(() => [Object.keys(requestBodyExamples.value).length > 1 ? (openBlock(), createElementBlock("div", _hoisted_4, [Object.keys(requestBodyExamples.value).length ? (openBlock(), createBlock(ExamplePicker_default, {
|
|
230
243
|
key: 0,
|
|
231
244
|
modelValue: selectedExampleKey.value,
|
|
232
245
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedExampleKey.value = $event),
|
|
@@ -241,7 +254,7 @@ var OperationCodeSample_vue_vue_type_script_setup_true_lang_default = /* @__PURE
|
|
|
241
254
|
class: "request-card dark-mode"
|
|
242
255
|
}, {
|
|
243
256
|
default: withCtx(() => [createVNode(unref(ScalarCardSection), { class: "request-card-simple" }, {
|
|
244
|
-
default: withCtx(() => [createElementVNode("div",
|
|
257
|
+
default: withCtx(() => [createElementVNode("div", _hoisted_5, [createVNode(HttpMethod_default, {
|
|
245
258
|
as: "span",
|
|
246
259
|
class: "request-method",
|
|
247
260
|
method: __props.method
|
package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationCodeSample.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown\n *\n * @defaults to shell/curl or a custom sample if one is available\n */\n selectedClient?: AvailableClients[number]\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport {\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n} from '@scalar/components/card'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarVirtualText } from '@scalar/components/virtual-text'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type AvailableClients } from '@scalar/snippetz'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(customCodeSamples.value, clientOptions),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/** If the globally selected client changes we can update the local one */\nwatch(\n () => selectedClient,\n (newClient) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n },\n)\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Emit the change if it's not a custom example\n if (option && !option.id.startsWith('custom')) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clients.length\"\n #actions>\n <ScalarCombobox\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base p-2\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n color: var(--scalar-color-1);\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OperationCodeSample.vue.script.js","names":["$slots"],"sources":["../../../../../src/v2/blocks/operation-code-sample/components/OperationCodeSample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type OperationCodeSampleProps = {\n /**\n * Integration type: determines if the code sample is displayed in a client environment\n * or in an API reference environment.\n */\n integration?: 'client' | 'reference'\n /**\n * List of all http clients formatted into option groups for the client selector\n */\n clientOptions: ClientOptionGroup[]\n /**\n * Pre-selected client, this will determine which client is initially selected in the dropdown.\n * Either a built-in client id (e.g. `js/fetch`) or a custom sample id (e.g. `custom/python`).\n *\n * Typed as a plain string: unioning the (large) client-id union with the `custom/...`\n * ids overflows TypeScript's union-complexity limit inside this component's `defineProps`.\n *\n * @defaults to a custom sample if one is available, otherwise shell/curl\n */\n selectedClient?: string\n /**\n * Which server from the spec to use for the code example\n */\n selectedServer?: ServerObject | null\n /**\n * The selected content type from the requestBody.content, this will determine which examples are available\n * as well as the content type of the code example\n *\n * @defaults to the first content type if not provided\n */\n selectedContentType?: string\n /**\n * Example name to use for resolving example values for parameters AND requestBody\n *\n * @example \"limited\"\n * ```ts\n * parameters: {\n * name: 'foobar',\n * in: 'query',\n * examples: {\n * limited: {\n * dataValue: 10,\n * }\n * }\n * },\n * body: {\n * content: {\n * 'application/json': {\n * examples: {\n * limited: {\n * dataValue: { foo: 'bar' },\n * }\n * }\n * }\n * }\n * }\n *\n * ```\n */\n selectedExample?: string\n /**\n * Event bus\n */\n eventBus: WorkspaceEventBus\n /**\n * The security schemes which are applicable to this operation\n */\n securitySchemes: SecuritySchemeObjectSecret[]\n /**\n * HTTP method of the operation\n */\n method: HttpMethodType\n /**\n * Path of the operation\n */\n path: string\n /**\n * De-referenced OpenAPI Operation object\n */\n operation: OperationObject\n /**\n * If true and there's no example, we will display a small card with the method and path only\n */\n fallback?: boolean\n /**\n * A method to generate the label of the block, should return an html string\n */\n generateLabel?: () => string\n /**\n * If true, render this as a webhook request example\n */\n isWebhook?: boolean\n /**\n * Workspace + document cookies\n */\n globalCookies?: XScalarCookie[]\n /**\n * When the request body schema uses oneOf/anyOf, use these selected variants\n * for the example snippet (e.g. from the schema dropdowns in the API reference).\n */\n requestBodyCompositionSelection?: Record<string, number>\n}\n\n/**\n * Request Example\n *\n * The core component for rendering a request example block,\n * this component does not have much of its own state but operates on props and custom events\n *\n * @event workspace:update:selected-client - Emitted when the selected client changes\n * @event scalar-update-selected-example - removed for now, we can bring it back when we need it\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport {\n ScalarCard,\n ScalarCardFooter,\n ScalarCardHeader,\n ScalarCardSection,\n} from '@scalar/components/card'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarVirtualText } from '@scalar/components/virtual-text'\nimport { freezeElement } from '@scalar/helpers/dom/freeze-element'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { operationToHar } from '@v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport HttpMethod from '@/v2/blocks/operation-code-sample/components/HttpMethod.vue'\nimport { filterClientsByQuery } from '@/v2/blocks/operation-code-sample/helpers/filter-clients-by-query'\nimport { findClient } from '@/v2/blocks/operation-code-sample/helpers/find-client'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '@/v2/blocks/operation-code-sample/types'\n\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport ExamplePicker from './ExamplePicker.vue'\n\nconst {\n integration,\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n requestBodyCompositionSelection,\n} = defineProps<OperationCodeSampleProps>()\n\ndefineSlots<{\n header: () => unknown\n footer: ({ exampleName }: { exampleName: string }) => unknown\n}>()\n\n/** Grab the examples for the given content type */\nconst requestBodyExamples = computed(() => {\n const content = getResolvedRef(operation.requestBody)?.content ?? {}\n const contentType = selectedContentType || Object.keys(content)[0]\n if (!contentType) return {}\n\n const examples = content[contentType]?.examples ?? {}\n\n return examples\n})\n\n/** The currently selected example key with v-model support */\nconst selectedExampleKey = defineModel<string>('selectedExample', {\n default: '',\n})\n\n// Set default value to the first example\nonBeforeMount(() => {\n selectedExampleKey.value ||= Object.keys(requestBodyExamples.value)[0] ?? ''\n})\n\n/** Reset the selected example key if the content type changes and the new content type doesn't have the previously selected example */\nwatch(\n () => selectedContentType,\n () => {\n if (\n !Object.keys(requestBodyExamples.value).includes(selectedExampleKey.value)\n ) {\n selectedExampleKey.value = Object.keys(requestBodyExamples.value)[0] ?? ''\n }\n },\n)\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/** Total number of available clients across all option groups */\nconst clientCount = computed(() =>\n clients.value.reduce((total, group) => total + group.options.length, 0),\n)\n\n/** The locally selected client which would include code samples from this operation only */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Generate HAR data for webhook requests */\nconst webhookHar = computed(() => {\n if (!isWebhook) return null\n\n try {\n return operationToHar({\n operation,\n method,\n path,\n example: selectedExampleKey.value,\n requestBodyCompositionSelection,\n defaultDisabledParameters: false,\n })\n } catch (error) {\n console.error('[webhookHar]', error)\n return null\n }\n})\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n defaultDisabledParameters: false,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExampleKey.value,\n globalCookies,\n requestBodyCompositionSelection,\n })\n})\n\n/** The language for the code block, used for syntax highlighting */\nconst codeBlockLanguage = computed(() => {\n if (isWebhook) {\n return webhookLanguage.value\n }\n\n return localSelectedClient.value?.lang\n})\n\n/** Determine the language for webhook content based on MIME type */\nconst webhookLanguage = computed<string>(() => {\n if (!webhookHar.value?.postData) return 'json'\n\n const contentType = webhookHar.value.postData.mimeType\n if (contentType?.includes('json')) return 'json'\n if (contentType?.includes('xml')) return 'xml'\n if (contentType?.includes('yaml') || contentType?.includes('yml'))\n return 'yaml'\n if (contentType?.includes('text/plain')) return 'text'\n\n return 'json'\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes))\n\n/** Grab the ref to freeze the ui as the clients change so there's no jump as the size of the dom changes */\nconst elem = ref<ComponentPublicInstance | null>(null)\n\n/** Set custom example, or update the selected HTTP client globally */\nconst selectClient = (option: ClientOption) => {\n // We need to freeze the ui to prevent scrolling as the clients change\n if (elem.value) {\n const unfreeze = freezeElement(elem.value.$el)\n setTimeout(() => {\n unfreeze()\n }, 300)\n }\n // Update to the local example\n localSelectedClient.value = option\n\n // Sync the selection globally so other operations follow along. Custom samples\n // sync too (keyed by language), so picking e.g. the Python SDK example here\n // shows the Python example on every operation that ships one.\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n// Virtualize the code block if it's too large\n// This prevents the entire app from freezing up if there's a massive example\n// We set a lower threshold here as code examples can get quite large\nconst VIRTUALIZATION_THRESHOLD = 20_000\n\nconst shouldVirtualize = computed(\n () => (generatedCode.value.length ?? 0) > VIRTUALIZATION_THRESHOLD,\n)\n\nconst id = useId()\n</script>\n<template>\n <ScalarCard\n v-if=\"generatedCode\"\n ref=\"elem\"\n class=\"request-card dark-mode\">\n <!-- Header -->\n <ScalarCardHeader class=\"pr-2.5\">\n <span class=\"sr-only\">Request Example for</span>\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <span\n v-if=\"generateLabel\"\n v-html=\"generateLabel()\" />\n <slot name=\"header\" />\n <!-- Client picker -->\n <template\n v-if=\"!isWebhook && clientCount\"\n #actions>\n <!-- Multiple clients: render a dropdown to switch between them -->\n <ScalarCombobox\n v-if=\"clientCount > 1\"\n class=\"max-h-80\"\n :filterFn=\"filterClientsByQuery\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"ui-open:rotate-180 mt-px size-3 transition-transform duration-100\"\n weight=\"bold\" />\n </ScalarButton>\n </ScalarCombobox>\n <!-- Single client: just show its label, no need for a dropdown -->\n <span\n v-else\n class=\"text-c-2 flex h-full w-fit items-center px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\">\n {{ localSelectedClient?.title }}\n </span>\n </template>\n </ScalarCardHeader>\n\n <!-- Code snippet -->\n <ScalarCardSection class=\"request-editor-section custom-scroll p-0\">\n <div\n :id=\"`${id}-example`\"\n class=\"code-snippet\">\n <ScalarCodeBlock\n v-if=\"!shouldVirtualize\"\n class=\"bg-b-2 h-full\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n containerClass=\"custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen\"\n contentClass=\"language-plaintext whitespace-pre font-code text-base p-2\"\n :lineHeight=\"20\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"Object.keys(requestBodyExamples).length > 1 || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"Object.keys(requestBodyExamples).length > 1\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n v-model=\"selectedExampleKey\"\n :examples=\"requestBodyExamples\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardFooter>\n </ScalarCard>\n\n <!-- Fallback card with just method and path in the case of no examples -->\n <ScalarCard\n v-else-if=\"fallback\"\n class=\"request-card dark-mode\">\n <ScalarCardSection class=\"request-card-simple\">\n <div class=\"request-header\">\n <HttpMethod\n as=\"span\"\n class=\"request-method\"\n :method=\"method\" />\n <slot name=\"header\" />\n </div>\n <slot\n :exampleName=\"selectedExampleKey\"\n name=\"footer\" />\n </ScalarCardSection>\n </ScalarCard>\n</template>\n<style scoped>\n.request-card {\n color: var(--scalar-color-1);\n font-size: var(--scalar-font-size-3);\n}\n.request-method {\n font-family: var(--scalar-font-code);\n text-transform: uppercase;\n margin-right: 6px;\n}\n.request-card-footer {\n display: flex;\n justify-content: flex-end;\n padding: 6px;\n flex-shrink: 0;\n position: relative;\n}\n.request-card-footer-addon {\n display: flex;\n align-items: center;\n\n flex: 1;\n min-width: 0;\n}\n.request-editor-section {\n display: flex;\n flex: 1;\n}\n.request-card-simple {\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding: 8px 8px 8px 12px;\n\n font-size: var(--scalar-small);\n}\n.code-snippet {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
import { type AvailableClients } from '@scalar/snippetz';
|
|
2
2
|
import type { ClientOption, CustomClientOption, CustomClientOptionGroup } from '../../../../v2/blocks/operation-code-sample/types';
|
|
3
3
|
export declare const DEFAULT_CLIENT = "shell/curl";
|
|
4
|
-
/** Type guard to check if a string is a valid client id */
|
|
5
|
-
export declare const isClient: (id: any) => id is AvailableClients[number];
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This function is used to determine which client should be initially selected in the
|
|
10
|
-
* request example block. It prioritizes a specific client ID if provided, otherwise
|
|
11
|
-
* falls back to the first available option.
|
|
5
|
+
* A selection the code sample picker understands: either a built-in client id
|
|
6
|
+
* (e.g. `js/fetch`) or a custom sample id (e.g. `custom/python`).
|
|
12
7
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
8
|
+
* The custom part is typed as `string & {}` rather than the `custom/${string}`
|
|
9
|
+
* template literal: unioning that template literal with the (very large) built-in
|
|
10
|
+
* client-id union trips TypeScript's "union too complex" limit inside Vue's
|
|
11
|
+
* `defineProps` macro. `string & {}` keeps editor hints for the known client ids
|
|
12
|
+
* without expanding the union.
|
|
13
|
+
*/
|
|
14
|
+
export type SelectedClientId = AvailableClients[number] | (string & {});
|
|
15
|
+
/** Type guard to check if a string is a valid built-in client id */
|
|
16
|
+
export declare const isClient: (id: any) => id is AvailableClients[number];
|
|
17
|
+
/** Type guard for any selection the picker can restore (built-in client or custom sample id) */
|
|
18
|
+
export declare const isSelectedClient: (id: any) => id is SelectedClientId;
|
|
19
|
+
/**
|
|
20
|
+
* Finds and returns the appropriate client option to select for an operation.
|
|
18
21
|
*
|
|
19
|
-
*
|
|
20
|
-
* ```typescript
|
|
21
|
-
* const clientGroups = [
|
|
22
|
-
* {
|
|
23
|
-
* label: 'JavaScript',
|
|
24
|
-
* options: [
|
|
25
|
-
* { id: 'js/fetch', label: 'Fetch API', lang: 'js' },
|
|
26
|
-
* { id: 'js/axios', label: 'Axios', lang: 'js' }
|
|
27
|
-
* ]
|
|
28
|
-
* }
|
|
29
|
-
* ]
|
|
22
|
+
* Selection rules, given the globally selected client/sample id:
|
|
30
23
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
24
|
+
* 1. A custom sample is selected (`custom/<lang>`): show the matching sample on
|
|
25
|
+
* this operation. If this operation has no sample for that exact language, we
|
|
26
|
+
* keep showing a custom sample (its first one) so the selection stays "global".
|
|
27
|
+
* 2. An explicit built-in client is selected: it wins, even when the operation
|
|
28
|
+
* also has custom samples. This includes the default client (`shell/curl`):
|
|
29
|
+
* a built-in id only reaches us through a real selection (config, persistence,
|
|
30
|
+
* or the picker), never as an implicit default, so a deliberate cURL pick must
|
|
31
|
+
* stick instead of snapping back to an SDK example.
|
|
32
|
+
* 3. Otherwise (nothing selected yet): prefer a custom sample when the operation
|
|
33
|
+
* has one, so custom examples are the default.
|
|
34
|
+
* 4. Fall back to the default built-in client, then the first option.
|
|
34
35
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* ```
|
|
36
|
+
* @param clientGroups - Array of client option groups, each containing a label and array of client options
|
|
37
|
+
* @param clientId - Optional selection to restore (e.g. 'js/fetch' or 'custom/python')
|
|
38
|
+
* @returns The selected client option, or undefined when there is nothing to select
|
|
39
39
|
*/
|
|
40
|
-
export declare const findClient: (clientGroups: CustomClientOptionGroup[], clientId?:
|
|
40
|
+
export declare const findClient: (clientGroups: CustomClientOptionGroup[], clientId?: SelectedClientId | undefined) => ClientOption | CustomClientOption | undefined;
|
|
41
41
|
//# sourceMappingURL=find-client.d.ts.map
|