@scalar/blocks 0.4.2 → 0.5.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.
Files changed (351) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +45 -0
  3. package/dist/code-example/components/CodeExample.vue.d.ts +5 -0
  4. package/dist/code-example/components/CodeExample.vue.d.ts.map +1 -1
  5. package/dist/code-example/components/CodeExample.vue.js +1 -1
  6. package/dist/code-example/components/CodeExample.vue.js.map +1 -1
  7. package/dist/code-example/components/CodeExample.vue.script.js +12 -9
  8. package/dist/code-example/components/CodeExample.vue.script.js.map +1 -1
  9. package/dist/code-example/helpers/operation-to-har/operation-to-har.d.ts.map +1 -1
  10. package/dist/code-example/helpers/operation-to-har/operation-to-har.js +1 -0
  11. package/dist/code-example/helpers/operation-to-har/operation-to-har.js.map +1 -1
  12. package/dist/code-example/helpers/operation-to-har/process-body.d.ts.map +1 -1
  13. package/dist/code-example/helpers/operation-to-har/process-body.js +51 -45
  14. package/dist/code-example/helpers/operation-to-har/process-body.js.map +1 -1
  15. package/dist/code-example/mount.d.ts +2 -0
  16. package/dist/code-example/mount.d.ts.map +1 -1
  17. package/dist/code-example/mount.js +3 -0
  18. package/dist/code-example/mount.js.map +1 -1
  19. package/dist/constants.js +1 -1
  20. package/dist/schema/LinkButton.vue.d.ts +14 -0
  21. package/dist/schema/LinkButton.vue.d.ts.map +1 -0
  22. package/dist/schema/LinkButton.vue.js +15 -0
  23. package/dist/schema/LinkButton.vue.js.map +1 -0
  24. package/dist/schema/RenderString.vue.d.ts +7 -0
  25. package/dist/schema/RenderString.vue.d.ts.map +1 -0
  26. package/dist/schema/RenderString.vue.js +7 -0
  27. package/dist/schema/RenderString.vue.js.map +1 -0
  28. package/dist/schema/RenderString.vue.script.js +14 -0
  29. package/dist/schema/RenderString.vue.script.js.map +1 -0
  30. package/dist/schema/Schema.vue.d.ts +50 -0
  31. package/dist/schema/Schema.vue.d.ts.map +1 -0
  32. package/dist/schema/Schema.vue.js +9 -0
  33. package/dist/schema/Schema.vue.js.map +1 -0
  34. package/dist/schema/Schema.vue.script.js +234 -0
  35. package/dist/schema/Schema.vue.script.js.map +1 -0
  36. package/dist/schema/SchemaCollapsedPreview.vue.d.ts +17 -0
  37. package/dist/schema/SchemaCollapsedPreview.vue.d.ts.map +1 -0
  38. package/dist/schema/SchemaCollapsedPreview.vue.js +7 -0
  39. package/dist/schema/SchemaCollapsedPreview.vue.js.map +1 -0
  40. package/dist/schema/SchemaCollapsedPreview.vue.script.js +28 -0
  41. package/dist/schema/SchemaCollapsedPreview.vue.script.js.map +1 -0
  42. package/dist/schema/SchemaComposition.vue.d.ts +42 -0
  43. package/dist/schema/SchemaComposition.vue.d.ts.map +1 -0
  44. package/dist/schema/SchemaComposition.vue.js +9 -0
  45. package/dist/schema/SchemaComposition.vue.js.map +1 -0
  46. package/dist/schema/SchemaComposition.vue.script.js +231 -0
  47. package/dist/schema/SchemaComposition.vue.script.js.map +1 -0
  48. package/dist/schema/SchemaEnumPropertyItem.vue.d.ts +8 -0
  49. package/dist/schema/SchemaEnumPropertyItem.vue.d.ts.map +1 -0
  50. package/dist/schema/SchemaEnumPropertyItem.vue.js +7 -0
  51. package/dist/schema/SchemaEnumPropertyItem.vue.js.map +1 -0
  52. package/dist/schema/SchemaEnumPropertyItem.vue.script.js +24 -0
  53. package/dist/schema/SchemaEnumPropertyItem.vue.script.js.map +1 -0
  54. package/dist/schema/SchemaEnums.vue.d.ts +11 -0
  55. package/dist/schema/SchemaEnums.vue.d.ts.map +1 -0
  56. package/dist/schema/SchemaEnums.vue.js +9 -0
  57. package/dist/schema/SchemaEnums.vue.js.map +1 -0
  58. package/dist/schema/SchemaEnums.vue.script.js +78 -0
  59. package/dist/schema/SchemaEnums.vue.script.js.map +1 -0
  60. package/dist/schema/SchemaGlyphPuck.vue.d.ts +33 -0
  61. package/dist/schema/SchemaGlyphPuck.vue.d.ts.map +1 -0
  62. package/dist/schema/SchemaGlyphPuck.vue.js +7 -0
  63. package/dist/schema/SchemaGlyphPuck.vue.js.map +1 -0
  64. package/dist/schema/SchemaGlyphPuck.vue.script.js +30 -0
  65. package/dist/schema/SchemaGlyphPuck.vue.script.js.map +1 -0
  66. package/dist/schema/SchemaGutterToggle.vue.d.ts +32 -0
  67. package/dist/schema/SchemaGutterToggle.vue.d.ts.map +1 -0
  68. package/dist/schema/SchemaGutterToggle.vue.js +7 -0
  69. package/dist/schema/SchemaGutterToggle.vue.js.map +1 -0
  70. package/dist/schema/SchemaGutterToggle.vue.script.js +43 -0
  71. package/dist/schema/SchemaGutterToggle.vue.script.js.map +1 -0
  72. package/dist/schema/SchemaHeading.vue.d.ts +9 -0
  73. package/dist/schema/SchemaHeading.vue.d.ts.map +1 -0
  74. package/dist/schema/SchemaHeading.vue.js +9 -0
  75. package/dist/schema/SchemaHeading.vue.js.map +1 -0
  76. package/dist/schema/SchemaHeading.vue.script.js +35 -0
  77. package/dist/schema/SchemaHeading.vue.script.js.map +1 -0
  78. package/dist/schema/SchemaObjectExampleCodeBlock.vue.d.ts +8 -0
  79. package/dist/schema/SchemaObjectExampleCodeBlock.vue.d.ts.map +1 -0
  80. package/dist/schema/SchemaObjectExampleCodeBlock.vue.js +7 -0
  81. package/dist/schema/SchemaObjectExampleCodeBlock.vue.js.map +1 -0
  82. package/dist/schema/SchemaObjectExampleCodeBlock.vue.script.js +48 -0
  83. package/dist/schema/SchemaObjectExampleCodeBlock.vue.script.js.map +1 -0
  84. package/dist/schema/SchemaObjectProperties.vue.d.ts +22 -0
  85. package/dist/schema/SchemaObjectProperties.vue.d.ts.map +1 -0
  86. package/dist/schema/SchemaObjectProperties.vue.js +7 -0
  87. package/dist/schema/SchemaObjectProperties.vue.js.map +1 -0
  88. package/dist/schema/SchemaObjectProperties.vue.script.js +207 -0
  89. package/dist/schema/SchemaObjectProperties.vue.script.js.map +1 -0
  90. package/dist/schema/SchemaProperty.vue.d.ts +88 -0
  91. package/dist/schema/SchemaProperty.vue.d.ts.map +1 -0
  92. package/dist/schema/SchemaProperty.vue.js +9 -0
  93. package/dist/schema/SchemaProperty.vue.js.map +1 -0
  94. package/dist/schema/SchemaProperty.vue.script.js +456 -0
  95. package/dist/schema/SchemaProperty.vue.script.js.map +1 -0
  96. package/dist/schema/SchemaPropertyDefault.vue.d.ts +7 -0
  97. package/dist/schema/SchemaPropertyDefault.vue.d.ts.map +1 -0
  98. package/dist/schema/SchemaPropertyDefault.vue.js +9 -0
  99. package/dist/schema/SchemaPropertyDefault.vue.js.map +1 -0
  100. package/dist/schema/SchemaPropertyDefault.vue.script.js +64 -0
  101. package/dist/schema/SchemaPropertyDefault.vue.script.js.map +1 -0
  102. package/dist/schema/SchemaPropertyDetail.vue.d.ts +22 -0
  103. package/dist/schema/SchemaPropertyDetail.vue.d.ts.map +1 -0
  104. package/dist/schema/SchemaPropertyDetail.vue.js +9 -0
  105. package/dist/schema/SchemaPropertyDetail.vue.js.map +1 -0
  106. package/dist/schema/SchemaPropertyDetail.vue.script.js +25 -0
  107. package/dist/schema/SchemaPropertyDetail.vue.script.js.map +1 -0
  108. package/dist/schema/SchemaPropertyExamples.vue.d.ts +8 -0
  109. package/dist/schema/SchemaPropertyExamples.vue.d.ts.map +1 -0
  110. package/dist/schema/SchemaPropertyExamples.vue.js +9 -0
  111. package/dist/schema/SchemaPropertyExamples.vue.js.map +1 -0
  112. package/dist/schema/SchemaPropertyExamples.vue.script.js +125 -0
  113. package/dist/schema/SchemaPropertyExamples.vue.script.js.map +1 -0
  114. package/dist/schema/SchemaPropertyHeading.vue.d.ts +59 -0
  115. package/dist/schema/SchemaPropertyHeading.vue.d.ts.map +1 -0
  116. package/dist/schema/SchemaPropertyHeading.vue.js +9 -0
  117. package/dist/schema/SchemaPropertyHeading.vue.js.map +1 -0
  118. package/dist/schema/SchemaPropertyHeading.vue.script.js +270 -0
  119. package/dist/schema/SchemaPropertyHeading.vue.script.js.map +1 -0
  120. package/dist/schema/SchemaPropertyPattern.vue.d.ts +7 -0
  121. package/dist/schema/SchemaPropertyPattern.vue.d.ts.map +1 -0
  122. package/dist/schema/SchemaPropertyPattern.vue.js +9 -0
  123. package/dist/schema/SchemaPropertyPattern.vue.js.map +1 -0
  124. package/dist/schema/SchemaPropertyPattern.vue.script.js +45 -0
  125. package/dist/schema/SchemaPropertyPattern.vue.script.js.map +1 -0
  126. package/dist/schema/SchemaRailPanel.vue.d.ts +35 -0
  127. package/dist/schema/SchemaRailPanel.vue.d.ts.map +1 -0
  128. package/dist/schema/SchemaRailPanel.vue.js +7 -0
  129. package/dist/schema/SchemaRailPanel.vue.js.map +1 -0
  130. package/dist/schema/SchemaRailPanel.vue.script.js +49 -0
  131. package/dist/schema/SchemaRailPanel.vue.script.js.map +1 -0
  132. package/dist/schema/components/CopyLinkButton.vue.d.ts +27 -0
  133. package/dist/schema/components/CopyLinkButton.vue.d.ts.map +1 -0
  134. package/dist/schema/components/CopyLinkButton.vue.js +7 -0
  135. package/dist/schema/components/CopyLinkButton.vue.js.map +1 -0
  136. package/dist/schema/components/CopyLinkButton.vue.script.js +26 -0
  137. package/dist/schema/components/CopyLinkButton.vue.script.js.map +1 -0
  138. package/dist/schema/components/WithBreadcrumb.vue.d.ts +19 -0
  139. package/dist/schema/components/WithBreadcrumb.vue.d.ts.map +1 -0
  140. package/dist/schema/components/WithBreadcrumb.vue.js +7 -0
  141. package/dist/schema/components/WithBreadcrumb.vue.js.map +1 -0
  142. package/dist/schema/components/WithBreadcrumb.vue.script.js +18 -0
  143. package/dist/schema/components/WithBreadcrumb.vue.script.js.map +1 -0
  144. package/dist/schema/expansion/index.d.ts +2 -0
  145. package/dist/schema/expansion/index.d.ts.map +1 -0
  146. package/dist/schema/expansion/index.js +2 -0
  147. package/dist/schema/helpers/dynamic-scope.d.ts +27 -0
  148. package/dist/schema/helpers/dynamic-scope.d.ts.map +1 -0
  149. package/dist/schema/helpers/dynamic-scope.js +8 -0
  150. package/dist/schema/helpers/dynamic-scope.js.map +1 -0
  151. package/dist/schema/helpers/format-example.d.ts +5 -0
  152. package/dist/schema/helpers/format-example.d.ts.map +1 -0
  153. package/dist/schema/helpers/format-example.js +12 -0
  154. package/dist/schema/helpers/format-example.js.map +1 -0
  155. package/dist/schema/helpers/format-value.d.ts +5 -0
  156. package/dist/schema/helpers/format-value.d.ts.map +1 -0
  157. package/dist/schema/helpers/format-value.js +8 -0
  158. package/dist/schema/helpers/format-value.js.map +1 -0
  159. package/dist/schema/helpers/get-compositions-to-render.d.ts +33 -0
  160. package/dist/schema/helpers/get-compositions-to-render.d.ts.map +1 -0
  161. package/dist/schema/helpers/get-compositions-to-render.js +39 -0
  162. package/dist/schema/helpers/get-compositions-to-render.js.map +1 -0
  163. package/dist/schema/helpers/get-discriminator-values.d.ts +4 -0
  164. package/dist/schema/helpers/get-discriminator-values.d.ts.map +1 -0
  165. package/dist/schema/helpers/get-discriminator-values.js +6 -0
  166. package/dist/schema/helpers/get-discriminator-values.js.map +1 -0
  167. package/dist/schema/helpers/get-enum-values.d.ts +9 -0
  168. package/dist/schema/helpers/get-enum-values.d.ts.map +1 -0
  169. package/dist/schema/helpers/get-enum-values.js +16 -0
  170. package/dist/schema/helpers/get-enum-values.js.map +1 -0
  171. package/dist/schema/helpers/get-property-description.d.ts +9 -0
  172. package/dist/schema/helpers/get-property-description.d.ts.map +1 -0
  173. package/dist/schema/helpers/get-property-description.js +27 -0
  174. package/dist/schema/helpers/get-property-description.js.map +1 -0
  175. package/dist/schema/helpers/get-ref-name.d.ts +24 -0
  176. package/dist/schema/helpers/get-ref-name.d.ts.map +1 -0
  177. package/dist/schema/helpers/get-ref-name.js +15 -0
  178. package/dist/schema/helpers/get-ref-name.js.map +1 -0
  179. package/dist/schema/helpers/get-schema-type.d.ts +13 -0
  180. package/dist/schema/helpers/get-schema-type.d.ts.map +1 -0
  181. package/dist/schema/helpers/get-schema-type.js +24 -0
  182. package/dist/schema/helpers/get-schema-type.js.map +1 -0
  183. package/dist/schema/helpers/get-type-signature-tokens.d.ts +48 -0
  184. package/dist/schema/helpers/get-type-signature-tokens.d.ts.map +1 -0
  185. package/dist/schema/helpers/get-type-signature-tokens.js +62 -0
  186. package/dist/schema/helpers/get-type-signature-tokens.js.map +1 -0
  187. package/dist/schema/helpers/has-complex-array-items.d.ts +10 -0
  188. package/dist/schema/helpers/has-complex-array-items.d.ts.map +1 -0
  189. package/dist/schema/helpers/has-complex-array-items.js +22 -0
  190. package/dist/schema/helpers/has-complex-array-items.js.map +1 -0
  191. package/dist/schema/helpers/index.d.ts +12 -0
  192. package/dist/schema/helpers/index.d.ts.map +1 -0
  193. package/dist/schema/helpers/index.js +12 -0
  194. package/dist/schema/helpers/is-empty-schema-object.d.ts +8 -0
  195. package/dist/schema/helpers/is-empty-schema-object.d.ts.map +1 -0
  196. package/dist/schema/helpers/is-empty-schema-object.js +11 -0
  197. package/dist/schema/helpers/is-empty-schema-object.js.map +1 -0
  198. package/dist/schema/helpers/is-model-linkable.d.ts +15 -0
  199. package/dist/schema/helpers/is-model-linkable.d.ts.map +1 -0
  200. package/dist/schema/helpers/is-model-linkable.js +13 -0
  201. package/dist/schema/helpers/is-model-linkable.js.map +1 -0
  202. package/dist/schema/helpers/is-on-schema-target-path.d.ts +3 -0
  203. package/dist/schema/helpers/is-on-schema-target-path.d.ts.map +1 -0
  204. package/dist/schema/helpers/is-on-schema-target-path.js +6 -0
  205. package/dist/schema/helpers/is-on-schema-target-path.js.map +1 -0
  206. package/dist/schema/helpers/is-type-object.d.ts +5 -0
  207. package/dist/schema/helpers/is-type-object.d.ts.map +1 -0
  208. package/dist/schema/helpers/is-type-object.js +15 -0
  209. package/dist/schema/helpers/is-type-object.js.map +1 -0
  210. package/dist/schema/helpers/merge-all-of-schemas.d.ts +12 -0
  211. package/dist/schema/helpers/merge-all-of-schemas.d.ts.map +1 -0
  212. package/dist/schema/helpers/merge-all-of-schemas.js +151 -0
  213. package/dist/schema/helpers/merge-all-of-schemas.js.map +1 -0
  214. package/dist/schema/helpers/normalize-object-composition.d.ts +9 -0
  215. package/dist/schema/helpers/normalize-object-composition.d.ts.map +1 -0
  216. package/dist/schema/helpers/normalize-object-composition.js +29 -0
  217. package/dist/schema/helpers/normalize-object-composition.js.map +1 -0
  218. package/dist/schema/helpers/optimize-value-for-display.d.ts +13 -0
  219. package/dist/schema/helpers/optimize-value-for-display.d.ts.map +1 -0
  220. package/dist/schema/helpers/optimize-value-for-display.js +64 -0
  221. package/dist/schema/helpers/optimize-value-for-display.js.map +1 -0
  222. package/dist/schema/helpers/partition-all-of-compositions.d.ts +32 -0
  223. package/dist/schema/helpers/partition-all-of-compositions.d.ts.map +1 -0
  224. package/dist/schema/helpers/partition-all-of-compositions.js +67 -0
  225. package/dist/schema/helpers/partition-all-of-compositions.js.map +1 -0
  226. package/dist/schema/helpers/schema-composition.d.ts +4 -0
  227. package/dist/schema/helpers/schema-composition.d.ts.map +1 -0
  228. package/dist/schema/helpers/schema-composition.js +11 -0
  229. package/dist/schema/helpers/schema-composition.js.map +1 -0
  230. package/dist/schema/helpers/schema-cycle.d.ts +31 -0
  231. package/dist/schema/helpers/schema-cycle.d.ts.map +1 -0
  232. package/dist/schema/helpers/schema-cycle.js +8 -0
  233. package/dist/schema/helpers/schema-cycle.js.map +1 -0
  234. package/dist/schema/helpers/schema-expansion.d.ts +89 -0
  235. package/dist/schema/helpers/schema-expansion.d.ts.map +1 -0
  236. package/dist/schema/helpers/schema-expansion.js +93 -0
  237. package/dist/schema/helpers/schema-expansion.js.map +1 -0
  238. package/dist/schema/helpers/schema-keyboard-nav.d.ts +23 -0
  239. package/dist/schema/helpers/schema-keyboard-nav.d.ts.map +1 -0
  240. package/dist/schema/helpers/schema-keyboard-nav.js +36 -0
  241. package/dist/schema/helpers/schema-keyboard-nav.js.map +1 -0
  242. package/dist/schema/helpers/schema-name.d.ts +27 -0
  243. package/dist/schema/helpers/schema-name.d.ts.map +1 -0
  244. package/dist/schema/helpers/schema-name.js +40 -0
  245. package/dist/schema/helpers/schema-name.js.map +1 -0
  246. package/dist/schema/helpers/should-display-description.d.ts +10 -0
  247. package/dist/schema/helpers/should-display-description.d.ts.map +1 -0
  248. package/dist/schema/helpers/should-display-description.js +6 -0
  249. package/dist/schema/helpers/should-display-description.js.map +1 -0
  250. package/dist/schema/helpers/should-display-heading.d.ts +11 -0
  251. package/dist/schema/helpers/should-display-heading.d.ts.map +1 -0
  252. package/dist/schema/helpers/should-display-heading.js +6 -0
  253. package/dist/schema/helpers/should-display-heading.js.map +1 -0
  254. package/dist/schema/helpers/should-render-array-item-composition.d.ts +10 -0
  255. package/dist/schema/helpers/should-render-array-item-composition.d.ts.map +1 -0
  256. package/dist/schema/helpers/should-render-array-item-composition.js +12 -0
  257. package/dist/schema/helpers/should-render-array-item-composition.js.map +1 -0
  258. package/dist/schema/helpers/sort-property-names.d.ts +23 -0
  259. package/dist/schema/helpers/sort-property-names.d.ts.map +1 -0
  260. package/dist/schema/helpers/sort-property-names.js +55 -0
  261. package/dist/schema/helpers/sort-property-names.js.map +1 -0
  262. package/dist/schema/helpers/unwrap-for-read.d.ts +48 -0
  263. package/dist/schema/helpers/unwrap-for-read.d.ts.map +1 -0
  264. package/dist/schema/helpers/unwrap-for-read.js +8 -0
  265. package/dist/schema/helpers/unwrap-for-read.js.map +1 -0
  266. package/dist/schema/index.d.ts +12 -0
  267. package/dist/schema/index.d.ts.map +1 -0
  268. package/dist/schema/index.js +11 -0
  269. package/dist/schema/localization/index.d.ts +59 -0
  270. package/dist/schema/localization/index.d.ts.map +1 -0
  271. package/dist/schema/localization/index.js +18 -0
  272. package/dist/schema/localization/index.js.map +1 -0
  273. package/dist/schema/localization/locales/ar.d.ts +58 -0
  274. package/dist/schema/localization/locales/ar.d.ts.map +1 -0
  275. package/dist/schema/localization/locales/ar.js +60 -0
  276. package/dist/schema/localization/locales/ar.js.map +1 -0
  277. package/dist/schema/localization/locales/de.d.ts +58 -0
  278. package/dist/schema/localization/locales/de.d.ts.map +1 -0
  279. package/dist/schema/localization/locales/de.js +60 -0
  280. package/dist/schema/localization/locales/de.js.map +1 -0
  281. package/dist/schema/localization/locales/en.d.ts +58 -0
  282. package/dist/schema/localization/locales/en.d.ts.map +1 -0
  283. package/dist/schema/localization/locales/en.js +60 -0
  284. package/dist/schema/localization/locales/en.js.map +1 -0
  285. package/dist/schema/localization/locales/es.d.ts +58 -0
  286. package/dist/schema/localization/locales/es.d.ts.map +1 -0
  287. package/dist/schema/localization/locales/es.js +60 -0
  288. package/dist/schema/localization/locales/es.js.map +1 -0
  289. package/dist/schema/localization/locales/fr.d.ts +58 -0
  290. package/dist/schema/localization/locales/fr.d.ts.map +1 -0
  291. package/dist/schema/localization/locales/fr.js +60 -0
  292. package/dist/schema/localization/locales/fr.js.map +1 -0
  293. package/dist/schema/localization/locales/pt.d.ts +58 -0
  294. package/dist/schema/localization/locales/pt.d.ts.map +1 -0
  295. package/dist/schema/localization/locales/pt.js +60 -0
  296. package/dist/schema/localization/locales/pt.js.map +1 -0
  297. package/dist/schema/localization/locales/ru.d.ts +58 -0
  298. package/dist/schema/localization/locales/ru.d.ts.map +1 -0
  299. package/dist/schema/localization/locales/ru.js +60 -0
  300. package/dist/schema/localization/locales/ru.js.map +1 -0
  301. package/dist/schema/localization/locales/zh-cn.d.ts +58 -0
  302. package/dist/schema/localization/locales/zh-cn.d.ts.map +1 -0
  303. package/dist/schema/localization/locales/zh-cn.js +60 -0
  304. package/dist/schema/localization/locales/zh-cn.js.map +1 -0
  305. package/dist/schema/localization/translations.d.ts +460 -0
  306. package/dist/schema/localization/translations.d.ts.map +1 -0
  307. package/dist/schema/localization/translations.js +23 -0
  308. package/dist/schema/localization/translations.js.map +1 -0
  309. package/dist/schema/request-body-composition-index.d.ts +8 -0
  310. package/dist/schema/request-body-composition-index.d.ts.map +1 -0
  311. package/dist/schema/request-body-composition-index.js +6 -0
  312. package/dist/schema/request-body-composition-index.js.map +1 -0
  313. package/dist/schema/schema-tree.bench.d.ts +2 -0
  314. package/dist/schema/schema-tree.bench.d.ts.map +1 -0
  315. package/dist/schema/types.d.ts +51 -0
  316. package/dist/schema/types.d.ts.map +1 -0
  317. package/dist/shared/Badge.vue.d.ts +17 -0
  318. package/dist/shared/Badge.vue.d.ts.map +1 -0
  319. package/dist/shared/Badge.vue.js +9 -0
  320. package/dist/shared/Badge.vue.js.map +1 -0
  321. package/dist/shared/Badge.vue.script.js +16 -0
  322. package/dist/shared/Badge.vue.script.js.map +1 -0
  323. package/dist/shared/ScreenReader.vue.d.ts +21 -0
  324. package/dist/shared/ScreenReader.vue.d.ts.map +1 -0
  325. package/dist/shared/ScreenReader.vue.js +7 -0
  326. package/dist/shared/ScreenReader.vue.js.map +1 -0
  327. package/dist/shared/ScreenReader.vue.script.js +19 -0
  328. package/dist/shared/ScreenReader.vue.script.js.map +1 -0
  329. package/dist/shared/index.d.ts +3 -0
  330. package/dist/shared/index.d.ts.map +1 -0
  331. package/dist/shared/index.js +3 -0
  332. package/dist/specification-extensions/ExtensionValue.vue.d.ts +13 -0
  333. package/dist/specification-extensions/ExtensionValue.vue.d.ts.map +1 -0
  334. package/dist/specification-extensions/ExtensionValue.vue.js +7 -0
  335. package/dist/specification-extensions/ExtensionValue.vue.js.map +1 -0
  336. package/dist/specification-extensions/ExtensionValue.vue.script.js +84 -0
  337. package/dist/specification-extensions/ExtensionValue.vue.script.js.map +1 -0
  338. package/dist/specification-extensions/SpecificationExtensions.vue.d.ts +9 -0
  339. package/dist/specification-extensions/SpecificationExtensions.vue.d.ts.map +1 -0
  340. package/dist/specification-extensions/SpecificationExtensions.vue.js +7 -0
  341. package/dist/specification-extensions/SpecificationExtensions.vue.js.map +1 -0
  342. package/dist/specification-extensions/SpecificationExtensions.vue.script.js +21 -0
  343. package/dist/specification-extensions/SpecificationExtensions.vue.script.js.map +1 -0
  344. package/dist/specification-extensions/index.d.ts +2 -0
  345. package/dist/specification-extensions/index.d.ts.map +1 -0
  346. package/dist/specification-extensions/index.js +2 -0
  347. package/dist/style.css +576 -15
  348. package/dist/styles/schema-tree.css +91 -0
  349. package/dist/styles/tailwind.config.css +22 -0
  350. package/dist/vue-styles.css +1 -1
  351. package/package.json +45 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @scalar/blocks
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#10443](https://github.com/scalar/scalar/pull/10443): Add a showExtensions allowlist to display OpenAPI extensions on operations, parameters, response headers, and schema fields without a custom plugin, with a schema-style value tree from the blocks package.
8
+ - [#10397](https://github.com/scalar/scalar/pull/10397): Extract the schema renderer into @scalar/blocks so other Scalar surfaces can reuse the schema tree while preserving API Reference behavior.
9
+
10
+ Keep the public API Reference Schema and SchemaProperty exports connected to extension plugins and deep-link navigation when mounted outside ApiReference.
11
+
12
+ Expose shared presentation components through @scalar/blocks/shared, group host integration APIs under schema/helpers and schema/expansion, and keep schema stories and visual regression coverage with Blocks.
13
+
14
+ Preserve literal toolbar icon types so Storybook previews can be type checked.
15
+
16
+ Pass schema navigation, extension rendering, and shared expansion state explicitly through props instead of providing or injecting host context.
17
+
18
+ ### Patch Changes
19
+
20
+ - [#10460](https://github.com/scalar/scalar/pull/10460): Preserve multipart file metadata in generated code examples, including arrays and composed schemas, read actual file bytes across code example targets, let HTTP clients set the multipart boundary, and preserve typed text fields without turning them into file attachments.
21
+ - [#10468](https://github.com/scalar/scalar/pull/10468): Stop the schema property copy-link button from taking width from a collapsed preview such as `{ compound, percentage }`. Its 24px hit box now overhangs the end of the line, so the row gives up only the icon and its gap, however the consuming app orders its stylesheets.
22
+
23
+ ## 0.4.3
24
+
25
+ ### Patch Changes
26
+
27
+ - [#10372](https://github.com/scalar/scalar/pull/10372): fix: improve keyboard and screen reader access to code blocks and multiselect comboboxes
28
+ - The code block scroller is exposed as a named group ("Code sample: Shell cURL" in the API Reference, localizable via `operation.codeSample`) so screen readers announce it when it receives focus
29
+ - The code block copy button now has a stable accessible name ("Copy Shell code") in every state, including while its visible label is hidden
30
+ - In multiselect comboboxes such as the auth scheme picker, Space toggles the active option while the search query is empty instead of hiding the whole list
31
+
3
32
  ## 0.4.2
4
33
 
5
34
  ## 0.4.1
package/README.md CHANGED
@@ -44,3 +44,48 @@ createCodeExample('#block', {
44
44
  },
45
45
  })
46
46
  ```
47
+
48
+ ## Schema tree
49
+
50
+ Render an OpenAPI schema in a Vue application using the same tree as API Reference:
51
+
52
+ ```vue
53
+ <script setup lang="ts">
54
+ import { Schema } from '@scalar/blocks/schema'
55
+ import { useSchemaExpansion } from '@scalar/blocks/schema/expansion'
56
+ import { ref } from 'vue'
57
+ import type { SchemaObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'
58
+ import '@scalar/blocks/style.css'
59
+
60
+ const { schema } = defineProps<{ schema: SchemaObject }>()
61
+ const scrollTargetId = ref('')
62
+ const expansion = useSchemaExpansion(scrollTargetId)
63
+ </script>
64
+
65
+ <template>
66
+ <div class="scalar-app">
67
+ <Schema :schema="schema" :eventBus="null" :options="{ hideModels: true }" :scrollTargetId="scrollTargetId" :expansion="expansion" />
68
+ </div>
69
+ </template>
70
+ ```
71
+
72
+ The tree supports nested properties, composition selectors, constraints, examples, and keyboard navigation. Pass schemas from the workspace store to retain resolved references. Display options are typed by `SchemaOptions`.
73
+
74
+ Translations inherit the host's `@scalar/localization` provider, including locale and custom overrides. Without a provider, labels use English.
75
+
76
+ Hosts pass `scrollTargetId`, `specificationExtension`, and `expansion` as props. Create a shared store with `useSchemaExpansion(scrollTargetId)` from `@scalar/blocks/schema/expansion` inside the host’s setup and pass it to each tree. Without an expansion prop, a standalone tree owns its own store. The extension component receives the schema through its `value` prop. Request-body composition selectors share selections with code samples through `REQUEST_BODY_COMPOSITION_INDEX_SYMBOL`.
77
+
78
+ ### Entry points
79
+
80
+ - `@scalar/blocks/schema` exposes the schema renderers, rail controls, `SchemaOptions`, translations, `SchemaRenderingProps`, and the composition-selection key.
81
+ - `@scalar/blocks/schema/expansion` exposes `useSchemaExpansion`, the expansion store and its controls, and breadcrumb node keys for hosts that render their own schema rows.
82
+ - `@scalar/blocks/schema/helpers` exposes the schema classification, composition, naming, ordering, and keyboard helpers shared with those host rows.
83
+ - `@scalar/blocks/shared` exposes the general-purpose `Badge` and `ScreenReader` components.
84
+
85
+ These entry points are supported package APIs. Implementation components such as composition selectors, enum lists, breadcrumbs, and copy-link buttons stay private to the schema renderer.
86
+
87
+ ### Schema workbench and snapshots
88
+
89
+ From the repository root, build the dependencies with `pnpm turbo --filter @scalar/blocks build`, then run `pnpm --filter @scalar/blocks dev:storybook` to browse the schema stories.
90
+
91
+ The stories, interactive snapshot tests, and checked-in baselines live together in `src/schema`. Run `pnpm --filter @scalar/blocks build:storybook` followed by `pnpm --filter @scalar/blocks test:e2e:storybook` with Docker running. The browser runs in the same Linux image as CI so snapshots compare consistently across host platforms. Use `test:e2e:storybook:update-snapshots` only for intentional visual changes.
@@ -13,6 +13,11 @@ export type CodeExampleProps = {
13
13
  clientPickerLabel?: string;
14
14
  /** Localized accessible name for the search field inside the client picker. */
15
15
  clientSearchLabel?: string;
16
+ /**
17
+ * Localized accessible name for the focusable code sample. The selected client's title is
18
+ * appended so the announcement also says which language the sample is in.
19
+ */
20
+ codeSampleLabel?: string;
16
21
  /**
17
22
  * Integration type: determines if the code sample is displayed in a client environment
18
23
  * or in an API reference environment.
@@ -1 +1 @@
1
- {"version":3,"file":"CodeExample.vue.d.ts","sourceRoot":"","sources":["../../../src/code-example/components/CodeExample.vue"],"names":[],"mappings":"AA0pBA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAUvE,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;AAkBrE,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,UAAU,CAAA;AAKjB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;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,MAAM,CAAA;IACd;;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,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAA;AAED;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;;;;;YAsCR,MAAM,OAAO;YACb,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO;EAusB3D,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"CodeExample.vue.d.ts","sourceRoot":"","sources":["../../../src/code-example/components/CodeExample.vue"],"names":[],"mappings":"AA6qBA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAUvE,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;AAkBrE,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,UAAU,CAAA;AAKjB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uFAAuF;IACvF,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;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,MAAM,CAAA;IACd;;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,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzD,CAAA;AAED;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;;;;;YAuCR,MAAM,OAAO;YACb,CAAC,EAAE,WAAW,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO;EAstB3D,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 e from "./CodeExample.vue.script.js";
2
2
  /* empty css */
3
3
  import t from "../../_virtual/_plugin-vue_export-helper.js";
4
4
  //#region src/code-example/components/CodeExample.vue
5
- var n = /*#__PURE__*/ t(e, [["__scopeId", "data-v-62318392"]]);
5
+ var n = /*#__PURE__*/ t(e, [["__scopeId", "data-v-24e941aa"]]);
6
6
  //#endregion
7
7
  export { n as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"CodeExample.vue.js","names":[],"sources":["../../../src/code-example/components/CodeExample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeExampleProps = {\n /** Localized status text shown when the selected example has no linked code sample. */\n codeSampleUnavailable?: string\n /**\n * Localized purpose of the client picker. It opens the button's accessible name and the\n * selected client's title is appended, so the name still contains the visible label.\n */\n clientPickerLabel?: string\n /** Localized accessible name for the search field inside the client picker. */\n clientSearchLabel?: string\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 * This is the document-wide selection: it is honored only when this operation defines an example\n * with the same key, so picking an example on one operation syncs the rest without blanking out\n * operations that do not share that key.\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: string\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 /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\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 workspace:update:selected-example - Emitted when the selected example changes, so other operations can sync\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 { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n getOperationExamples,\n resolveOperationExamples,\n} from '@scalar/workspace-store/helpers/operation-examples'\nimport {\n useExampleVisibility,\n useExternalExamples,\n} from '@scalar/workspace-store/helpers/use-external-examples'\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.2/strict/openapi-document'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n watchEffect,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport { filterClientsByQuery } from '../helpers/filter-clients-by-query'\nimport { findClient } from '../helpers/find-client'\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport { getClients } from '../helpers/get-clients'\nimport { getCustomCodeSamples } from '../helpers/get-custom-code-samples'\nimport { getSecrets } from '../helpers/get-secrets'\nimport { operationToHar } from '../helpers/operation-to-har/operation-to-har'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '../types'\nimport ExamplePicker from './ExamplePicker.vue'\nimport HttpMethod from './HttpMethod.vue'\n\nconst {\n integration,\n codeSampleUnavailable = 'No code sample available for this example.',\n clientPickerLabel = 'Change code sample language',\n clientSearchLabel = 'Search clients',\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n selectedExample,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n} = defineProps<CodeExampleProps>()\n\nconst emit = defineEmits<{\n /**\n * Emitted whenever the example key actually shown for this operation changes.\n *\n * This is the resolved local key (not the raw document-wide selection), so layouts that render\n * the test-request button outside this component can open the client with the same example the\n * snippet displays.\n */\n (e: 'update:exampleKey', value: string): void\n}>()\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/**\n * The example key actually shown for this operation.\n *\n * `selectedExample` is the document-wide selection that syncs across operations. We honor it only\n * when this operation actually defines that key, otherwise we keep the local example: a selection\n * on one operation should never blank out an operation that does not share the same example.\n */\nconst localExampleKey = ref('')\n\n/** Resolve the key to display, preferring the document-wide selection when this operation has it */\nconst resolveExampleKey = (preferred: string | undefined): string => {\n const keys = Object.keys(requestBodyExamples.value)\n if (preferred && keys.includes(preferred)) {\n return preferred\n }\n // Keep the current local example when it is still valid, otherwise fall back to the first one\n if (localExampleKey.value && keys.includes(localExampleKey.value)) {\n return localExampleKey.value\n }\n return keys[0] ?? ''\n}\n\n// Set the initial example from the document-wide selection, falling back to the first example\nonBeforeMount(() => {\n localExampleKey.value = resolveExampleKey(selectedExample)\n})\n\n// Follow the document-wide selection when it changes and this operation has that example\nwatch(\n () => selectedExample,\n (preferred) => {\n localExampleKey.value = resolveExampleKey(preferred)\n },\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(localExampleKey.value)\n ) {\n // Re-resolve so the new content type still follows the document-wide selection when it has\n // that key, instead of always snapping back to the first example\n localExampleKey.value = resolveExampleKey(selectedExample)\n }\n },\n)\n\n// Keep the parent informed of the resolved key so a test-request button rendered outside this\n// component (e.g. the classic layout header) opens the client with the example the snippet shows\nwatchEffect(() => {\n emit('update:exampleKey', localExampleKey.value)\n})\n\n/** Select an example locally and sync the choice across the document */\nconst selectExample = (key: string) => {\n localExampleKey.value = key\n eventBus.emit('workspace:update:selected-example', key)\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/**\n * Accessible name for the client picker.\n *\n * On its own the button reads as its current value (\"C Libcurl\"), which never\n * says what activating it does. The visible title stays part of the name so it\n * still matches what is on screen.\n */\nconst clientPickerAriaLabel = computed(() =>\n [clientPickerLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\nconst elem = ref<ComponentPublicInstance | null>(null)\nconst visible = useExampleVisibility(elem)\nconst externalExamples = useExternalExamples(\n () =>\n getOperationExamples(operation, localExampleKey.value, selectedContentType),\n () => visible.value,\n)\nconst resolvedOperation = computed(() =>\n resolveOperationExamples(\n operation,\n localExampleKey.value,\n selectedContentType,\n externalExamples.resolve,\n ),\n)\n\n/** Keep the picker available because it also selects the example opened by Test Request. */\nconst showExamplePicker = computed(\n () => Object.keys(requestBodyExamples.value).length > 1,\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: resolvedOperation.value,\n method,\n path,\n example: localExampleKey.value,\n openapiVersion,\n requestBodyCompositionSelection,\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\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 | null>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation: resolvedOperation.value,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: localExampleKey.value,\n globalCookies,\n openapiVersion,\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/** 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=\"\n generatedCode === null || generatedCode || externalExamples.pending.value\n \"\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 :inputLabel=\"clientSearchLabel\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n :aria-label=\"clientPickerAriaLabel\"\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 v-if=\"externalExamples.pending.value\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamples.failed.value\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"externalExamples.retry\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n <div\n v-else-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ codeSampleUnavailable }}\n </div>\n <div\n v-else\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 aria-label=\"Request code sample\"\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 role=\"region\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"showExamplePicker || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"showExamplePicker\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n :examples=\"requestBodyExamples\"\n :modelValue=\"localExampleKey\"\n @update:modelValue=\"selectExample\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"localExampleKey\"\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=\"localExampleKey\"\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 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":"CodeExample.vue.js","names":[],"sources":["../../../src/code-example/components/CodeExample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeExampleProps = {\n /** Localized status text shown when the selected example has no linked code sample. */\n codeSampleUnavailable?: string\n /**\n * Localized purpose of the client picker. It opens the button's accessible name and the\n * selected client's title is appended, so the name still contains the visible label.\n */\n clientPickerLabel?: string\n /** Localized accessible name for the search field inside the client picker. */\n clientSearchLabel?: string\n /**\n * Localized accessible name for the focusable code sample. The selected client's title is\n * appended so the announcement also says which language the sample is in.\n */\n codeSampleLabel?: string\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 * This is the document-wide selection: it is honored only when this operation defines an example\n * with the same key, so picking an example on one operation syncs the rest without blanking out\n * operations that do not share that key.\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: string\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 /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\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 workspace:update:selected-example - Emitted when the selected example changes, so other operations can sync\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 { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n getOperationExamples,\n resolveOperationExamples,\n} from '@scalar/workspace-store/helpers/operation-examples'\nimport {\n useExampleVisibility,\n useExternalExamples,\n} from '@scalar/workspace-store/helpers/use-external-examples'\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.2/strict/openapi-document'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n watchEffect,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport { filterClientsByQuery } from '../helpers/filter-clients-by-query'\nimport { findClient } from '../helpers/find-client'\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport { getClients } from '../helpers/get-clients'\nimport { getCustomCodeSamples } from '../helpers/get-custom-code-samples'\nimport { getSecrets } from '../helpers/get-secrets'\nimport { operationToHar } from '../helpers/operation-to-har/operation-to-har'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '../types'\nimport ExamplePicker from './ExamplePicker.vue'\nimport HttpMethod from './HttpMethod.vue'\n\nconst {\n integration,\n codeSampleUnavailable = 'No code sample available for this example.',\n clientPickerLabel = 'Change code sample language',\n clientSearchLabel = 'Search clients',\n codeSampleLabel = 'Code sample',\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n selectedExample,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n} = defineProps<CodeExampleProps>()\n\nconst emit = defineEmits<{\n /**\n * Emitted whenever the example key actually shown for this operation changes.\n *\n * This is the resolved local key (not the raw document-wide selection), so layouts that render\n * the test-request button outside this component can open the client with the same example the\n * snippet displays.\n */\n (e: 'update:exampleKey', value: string): void\n}>()\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/**\n * The example key actually shown for this operation.\n *\n * `selectedExample` is the document-wide selection that syncs across operations. We honor it only\n * when this operation actually defines that key, otherwise we keep the local example: a selection\n * on one operation should never blank out an operation that does not share the same example.\n */\nconst localExampleKey = ref('')\n\n/** Resolve the key to display, preferring the document-wide selection when this operation has it */\nconst resolveExampleKey = (preferred: string | undefined): string => {\n const keys = Object.keys(requestBodyExamples.value)\n if (preferred && keys.includes(preferred)) {\n return preferred\n }\n // Keep the current local example when it is still valid, otherwise fall back to the first one\n if (localExampleKey.value && keys.includes(localExampleKey.value)) {\n return localExampleKey.value\n }\n return keys[0] ?? ''\n}\n\n// Set the initial example from the document-wide selection, falling back to the first example\nonBeforeMount(() => {\n localExampleKey.value = resolveExampleKey(selectedExample)\n})\n\n// Follow the document-wide selection when it changes and this operation has that example\nwatch(\n () => selectedExample,\n (preferred) => {\n localExampleKey.value = resolveExampleKey(preferred)\n },\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(localExampleKey.value)\n ) {\n // Re-resolve so the new content type still follows the document-wide selection when it has\n // that key, instead of always snapping back to the first example\n localExampleKey.value = resolveExampleKey(selectedExample)\n }\n },\n)\n\n// Keep the parent informed of the resolved key so a test-request button rendered outside this\n// component (e.g. the classic layout header) opens the client with the example the snippet shows\nwatchEffect(() => {\n emit('update:exampleKey', localExampleKey.value)\n})\n\n/** Select an example locally and sync the choice across the document */\nconst selectExample = (key: string) => {\n localExampleKey.value = key\n eventBus.emit('workspace:update:selected-example', key)\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/**\n * Accessible name for the client picker.\n *\n * On its own the button reads as its current value (\"C Libcurl\"), which never\n * says what activating it does. The visible title stays part of the name so it\n * still matches what is on screen.\n */\nconst clientPickerAriaLabel = computed(() =>\n [clientPickerLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\n/**\n * Accessible name for the focusable code sample, e.g. \"Code sample: Shell cURL\".\n *\n * Screen readers announce only the name and role when focus lands on the scroller, so the\n * name tells the user both what the region is and which client it is generated for.\n */\nconst codeSampleAriaLabel = computed(() =>\n [codeSampleLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\nconst elem = ref<ComponentPublicInstance | null>(null)\nconst visible = useExampleVisibility(elem)\nconst externalExamples = useExternalExamples(\n () =>\n getOperationExamples(operation, localExampleKey.value, selectedContentType),\n () => visible.value,\n)\nconst resolvedOperation = computed(() =>\n resolveOperationExamples(\n operation,\n localExampleKey.value,\n selectedContentType,\n externalExamples.resolve,\n ),\n)\n\n/** Keep the picker available because it also selects the example opened by Test Request. */\nconst showExamplePicker = computed(\n () => Object.keys(requestBodyExamples.value).length > 1,\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: resolvedOperation.value,\n method,\n path,\n example: localExampleKey.value,\n openapiVersion,\n requestBodyCompositionSelection,\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\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 | null>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation: resolvedOperation.value,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: localExampleKey.value,\n globalCookies,\n openapiVersion,\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/** 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=\"\n generatedCode === null || generatedCode || externalExamples.pending.value\n \"\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 :inputLabel=\"clientSearchLabel\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n :aria-label=\"clientPickerAriaLabel\"\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 v-if=\"externalExamples.pending.value\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamples.failed.value\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"externalExamples.retry\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n <div\n v-else-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ codeSampleUnavailable }}\n </div>\n <div\n v-else\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 :label=\"codeSampleAriaLabel\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n aria-label=\"Request code sample\"\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 role=\"region\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"showExamplePicker || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"showExamplePicker\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n :examples=\"requestBodyExamples\"\n :modelValue=\"localExampleKey\"\n @update:modelValue=\"selectExample\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"localExampleKey\"\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=\"localExampleKey\"\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 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":""}
@@ -40,6 +40,7 @@ var M = ["innerHTML"], N = {
40
40
  codeSampleUnavailable: { default: "No code sample available for this example." },
41
41
  clientPickerLabel: { default: "Change code sample language" },
42
42
  clientSearchLabel: { default: "Search clients" },
43
+ codeSampleLabel: { default: "Code sample" },
43
44
  integration: {},
44
45
  clientOptions: {},
45
46
  selectedClient: {},
@@ -83,7 +84,7 @@ var M = ["innerHTML"], N = {
83
84
  let n = t(G.value, e);
84
85
  n && (q.value = n);
85
86
  });
86
- let pe = s(() => [m.clientPickerLabel, q.value?.title].filter(Boolean).join(": ")), J = g(null), me = A(J), Y = j(() => O(m.operation, H.value, m.selectedContentType), () => me.value), X = s(() => k(m.operation, H.value, m.selectedContentType, Y.resolve)), Z = s(() => Object.keys(V.value).length > 1), Q = s(() => {
87
+ let pe = s(() => [m.clientPickerLabel, q.value?.title].filter(Boolean).join(": ")), me = s(() => [m.codeSampleLabel, q.value?.title].filter(Boolean).join(": ")), J = g(null), he = A(J), Y = j(() => O(m.operation, H.value, m.selectedContentType), () => he.value), X = s(() => k(m.operation, H.value, m.selectedContentType, Y.resolve)), Z = s(() => Object.keys(V.value).length > 1), Q = s(() => {
87
88
  if (!m.isWebhook) return null;
88
89
  try {
89
90
  return n({
@@ -113,11 +114,11 @@ var M = ["innerHTML"], N = {
113
114
  globalCookies: m.globalCookies,
114
115
  openapiVersion: m.openapiVersion,
115
116
  requestBodyCompositionSelection: m.requestBodyCompositionSelection
116
- })), he = s(() => m.isWebhook ? ge.value : q.value?.lang), ge = s(() => {
117
+ })), ge = s(() => m.isWebhook ? _e.value : q.value?.lang), _e = s(() => {
117
118
  if (!Q.value?.postData) return "json";
118
119
  let e = Q.value.postData.mimeType;
119
120
  return e?.includes("json") ? "json" : e?.includes("xml") ? "xml" : e?.includes("yaml") || e?.includes("yml") ? "yaml" : e?.includes("text/plain") ? "text" : "json";
120
- }), _e = s(() => i(m.securitySchemes)), ve = (e) => {
121
+ }), ve = s(() => i(m.securitySchemes)), ye = (e) => {
121
122
  if (J.value) {
122
123
  let e = de(J.value.$el);
123
124
  setTimeout(() => {
@@ -125,7 +126,7 @@ var M = ["innerHTML"], N = {
125
126
  }, 300);
126
127
  }
127
128
  q.value = e, e && m.eventBus.emit("workspace:update:selected-client", e.id);
128
- }, ye = s(() => ($.value?.length ?? 0) > 2e4), be = b();
129
+ }, be = s(() => ($.value?.length ?? 0) > 2e4), xe = b();
129
130
  return (t, n) => $.value === null || $.value || y(Y).pending.value ? (h(), c(y(w), {
130
131
  key: 0,
131
132
  ref_key: "elem",
@@ -159,7 +160,7 @@ var M = ["innerHTML"], N = {
159
160
  options: G.value,
160
161
  placement: "bottom-end",
161
162
  teleport: "",
162
- "onUpdate:modelValue": n[0] ||= (e) => ve(e)
163
+ "onUpdate:modelValue": n[0] ||= (e) => ye(e)
163
164
  }, {
164
165
  default: S(() => [p(y(C), {
165
166
  "aria-label": pe.value,
@@ -192,9 +193,9 @@ var M = ["innerHTML"], N = {
192
193
  _: 1
193
194
  }, 8, ["onClick"])], 64)) : (h(), u(o, { key: 1 }, [f("Loading example…")], 64))])) : $.value === null ? (h(), u("div", F, v(m.codeSampleUnavailable), 1)) : (h(), u("div", {
194
195
  key: 2,
195
- id: `${y(be)}-example`,
196
+ id: `${y(xe)}-example`,
196
197
  class: "code-snippet"
197
- }, [ye.value ? (h(), c(y(ue), {
198
+ }, [be.value ? (h(), c(y(ue), {
198
199
  key: 1,
199
200
  "aria-label": "Request code sample",
200
201
  containerClass: "custom-scroll scalar-code-block border rounded-b flex flex-1 max-h-screen",
@@ -206,12 +207,14 @@ var M = ["innerHTML"], N = {
206
207
  key: 0,
207
208
  class: "bg-b-2 h-full",
208
209
  content: $.value,
209
- hideCredentials: _e.value,
210
- lang: he.value,
210
+ hideCredentials: ve.value,
211
+ label: me.value,
212
+ lang: ge.value,
211
213
  lineNumbers: ""
212
214
  }, null, 8, [
213
215
  "content",
214
216
  "hideCredentials",
217
+ "label",
215
218
  "lang"
216
219
  ]))], 8, I))]),
217
220
  _: 1
@@ -1 +1 @@
1
- {"version":3,"file":"CodeExample.vue.script.js","names":["$slots"],"sources":["../../../src/code-example/components/CodeExample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeExampleProps = {\n /** Localized status text shown when the selected example has no linked code sample. */\n codeSampleUnavailable?: string\n /**\n * Localized purpose of the client picker. It opens the button's accessible name and the\n * selected client's title is appended, so the name still contains the visible label.\n */\n clientPickerLabel?: string\n /** Localized accessible name for the search field inside the client picker. */\n clientSearchLabel?: string\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 * This is the document-wide selection: it is honored only when this operation defines an example\n * with the same key, so picking an example on one operation syncs the rest without blanking out\n * operations that do not share that key.\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: string\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 /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\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 workspace:update:selected-example - Emitted when the selected example changes, so other operations can sync\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 { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n getOperationExamples,\n resolveOperationExamples,\n} from '@scalar/workspace-store/helpers/operation-examples'\nimport {\n useExampleVisibility,\n useExternalExamples,\n} from '@scalar/workspace-store/helpers/use-external-examples'\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.2/strict/openapi-document'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n watchEffect,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport { filterClientsByQuery } from '../helpers/filter-clients-by-query'\nimport { findClient } from '../helpers/find-client'\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport { getClients } from '../helpers/get-clients'\nimport { getCustomCodeSamples } from '../helpers/get-custom-code-samples'\nimport { getSecrets } from '../helpers/get-secrets'\nimport { operationToHar } from '../helpers/operation-to-har/operation-to-har'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '../types'\nimport ExamplePicker from './ExamplePicker.vue'\nimport HttpMethod from './HttpMethod.vue'\n\nconst {\n integration,\n codeSampleUnavailable = 'No code sample available for this example.',\n clientPickerLabel = 'Change code sample language',\n clientSearchLabel = 'Search clients',\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n selectedExample,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n} = defineProps<CodeExampleProps>()\n\nconst emit = defineEmits<{\n /**\n * Emitted whenever the example key actually shown for this operation changes.\n *\n * This is the resolved local key (not the raw document-wide selection), so layouts that render\n * the test-request button outside this component can open the client with the same example the\n * snippet displays.\n */\n (e: 'update:exampleKey', value: string): void\n}>()\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/**\n * The example key actually shown for this operation.\n *\n * `selectedExample` is the document-wide selection that syncs across operations. We honor it only\n * when this operation actually defines that key, otherwise we keep the local example: a selection\n * on one operation should never blank out an operation that does not share the same example.\n */\nconst localExampleKey = ref('')\n\n/** Resolve the key to display, preferring the document-wide selection when this operation has it */\nconst resolveExampleKey = (preferred: string | undefined): string => {\n const keys = Object.keys(requestBodyExamples.value)\n if (preferred && keys.includes(preferred)) {\n return preferred\n }\n // Keep the current local example when it is still valid, otherwise fall back to the first one\n if (localExampleKey.value && keys.includes(localExampleKey.value)) {\n return localExampleKey.value\n }\n return keys[0] ?? ''\n}\n\n// Set the initial example from the document-wide selection, falling back to the first example\nonBeforeMount(() => {\n localExampleKey.value = resolveExampleKey(selectedExample)\n})\n\n// Follow the document-wide selection when it changes and this operation has that example\nwatch(\n () => selectedExample,\n (preferred) => {\n localExampleKey.value = resolveExampleKey(preferred)\n },\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(localExampleKey.value)\n ) {\n // Re-resolve so the new content type still follows the document-wide selection when it has\n // that key, instead of always snapping back to the first example\n localExampleKey.value = resolveExampleKey(selectedExample)\n }\n },\n)\n\n// Keep the parent informed of the resolved key so a test-request button rendered outside this\n// component (e.g. the classic layout header) opens the client with the example the snippet shows\nwatchEffect(() => {\n emit('update:exampleKey', localExampleKey.value)\n})\n\n/** Select an example locally and sync the choice across the document */\nconst selectExample = (key: string) => {\n localExampleKey.value = key\n eventBus.emit('workspace:update:selected-example', key)\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/**\n * Accessible name for the client picker.\n *\n * On its own the button reads as its current value (\"C Libcurl\"), which never\n * says what activating it does. The visible title stays part of the name so it\n * still matches what is on screen.\n */\nconst clientPickerAriaLabel = computed(() =>\n [clientPickerLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\nconst elem = ref<ComponentPublicInstance | null>(null)\nconst visible = useExampleVisibility(elem)\nconst externalExamples = useExternalExamples(\n () =>\n getOperationExamples(operation, localExampleKey.value, selectedContentType),\n () => visible.value,\n)\nconst resolvedOperation = computed(() =>\n resolveOperationExamples(\n operation,\n localExampleKey.value,\n selectedContentType,\n externalExamples.resolve,\n ),\n)\n\n/** Keep the picker available because it also selects the example opened by Test Request. */\nconst showExamplePicker = computed(\n () => Object.keys(requestBodyExamples.value).length > 1,\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: resolvedOperation.value,\n method,\n path,\n example: localExampleKey.value,\n openapiVersion,\n requestBodyCompositionSelection,\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\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 | null>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation: resolvedOperation.value,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: localExampleKey.value,\n globalCookies,\n openapiVersion,\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/** 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=\"\n generatedCode === null || generatedCode || externalExamples.pending.value\n \"\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 :inputLabel=\"clientSearchLabel\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n :aria-label=\"clientPickerAriaLabel\"\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 v-if=\"externalExamples.pending.value\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamples.failed.value\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"externalExamples.retry\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n <div\n v-else-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ codeSampleUnavailable }}\n </div>\n <div\n v-else\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 aria-label=\"Request code sample\"\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 role=\"region\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"showExamplePicker || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"showExamplePicker\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n :examples=\"requestBodyExamples\"\n :modelValue=\"localExampleKey\"\n @update:modelValue=\"selectExample\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"localExampleKey\"\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=\"localExampleKey\"\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 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":"CodeExample.vue.script.js","names":["$slots"],"sources":["../../../src/code-example/components/CodeExample.vue"],"sourcesContent":["<script lang=\"ts\">\nexport type CodeExampleProps = {\n /** Localized status text shown when the selected example has no linked code sample. */\n codeSampleUnavailable?: string\n /**\n * Localized purpose of the client picker. It opens the button's accessible name and the\n * selected client's title is appended, so the name still contains the visible label.\n */\n clientPickerLabel?: string\n /** Localized accessible name for the search field inside the client picker. */\n clientSearchLabel?: string\n /**\n * Localized accessible name for the focusable code sample. The selected client's title is\n * appended so the announcement also says which language the sample is in.\n */\n codeSampleLabel?: string\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 * This is the document-wide selection: it is honored only when this operation defines an example\n * with the same key, so picking an example on one operation syncs the rest without blanking out\n * operations that do not share that key.\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: string\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 /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\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 workspace:update:selected-example - Emitted when the selected example changes, so other operations can sync\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 { ScalarIconCaretDown } from '@scalar/icons'\nimport { type WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n getOperationExamples,\n resolveOperationExamples,\n} from '@scalar/workspace-store/helpers/operation-examples'\nimport {\n useExampleVisibility,\n useExternalExamples,\n} from '@scalar/workspace-store/helpers/use-external-examples'\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.2/strict/openapi-document'\nimport {\n computed,\n onBeforeMount,\n ref,\n useId,\n watch,\n watchEffect,\n type ComponentPublicInstance,\n} from 'vue'\n\nimport { filterClientsByQuery } from '../helpers/filter-clients-by-query'\nimport { findClient } from '../helpers/find-client'\nimport { generateCodeSnippet } from '../helpers/generate-code-snippet'\nimport { getClients } from '../helpers/get-clients'\nimport { getCustomCodeSamples } from '../helpers/get-custom-code-samples'\nimport { getSecrets } from '../helpers/get-secrets'\nimport { operationToHar } from '../helpers/operation-to-har/operation-to-har'\nimport type {\n ClientOption,\n ClientOptionGroup,\n CustomClientOption,\n} from '../types'\nimport ExamplePicker from './ExamplePicker.vue'\nimport HttpMethod from './HttpMethod.vue'\n\nconst {\n integration,\n codeSampleUnavailable = 'No code sample available for this example.',\n clientPickerLabel = 'Change code sample language',\n clientSearchLabel = 'Search clients',\n codeSampleLabel = 'Code sample',\n clientOptions,\n selectedClient,\n selectedServer = null,\n selectedContentType,\n selectedExample,\n securitySchemes = [],\n method,\n eventBus,\n path,\n operation,\n isWebhook,\n generateLabel,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n} = defineProps<CodeExampleProps>()\n\nconst emit = defineEmits<{\n /**\n * Emitted whenever the example key actually shown for this operation changes.\n *\n * This is the resolved local key (not the raw document-wide selection), so layouts that render\n * the test-request button outside this component can open the client with the same example the\n * snippet displays.\n */\n (e: 'update:exampleKey', value: string): void\n}>()\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/**\n * The example key actually shown for this operation.\n *\n * `selectedExample` is the document-wide selection that syncs across operations. We honor it only\n * when this operation actually defines that key, otherwise we keep the local example: a selection\n * on one operation should never blank out an operation that does not share the same example.\n */\nconst localExampleKey = ref('')\n\n/** Resolve the key to display, preferring the document-wide selection when this operation has it */\nconst resolveExampleKey = (preferred: string | undefined): string => {\n const keys = Object.keys(requestBodyExamples.value)\n if (preferred && keys.includes(preferred)) {\n return preferred\n }\n // Keep the current local example when it is still valid, otherwise fall back to the first one\n if (localExampleKey.value && keys.includes(localExampleKey.value)) {\n return localExampleKey.value\n }\n return keys[0] ?? ''\n}\n\n// Set the initial example from the document-wide selection, falling back to the first example\nonBeforeMount(() => {\n localExampleKey.value = resolveExampleKey(selectedExample)\n})\n\n// Follow the document-wide selection when it changes and this operation has that example\nwatch(\n () => selectedExample,\n (preferred) => {\n localExampleKey.value = resolveExampleKey(preferred)\n },\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(localExampleKey.value)\n ) {\n // Re-resolve so the new content type still follows the document-wide selection when it has\n // that key, instead of always snapping back to the first example\n localExampleKey.value = resolveExampleKey(selectedExample)\n }\n },\n)\n\n// Keep the parent informed of the resolved key so a test-request button rendered outside this\n// component (e.g. the classic layout header) opens the client with the example the snippet shows\nwatchEffect(() => {\n emit('update:exampleKey', localExampleKey.value)\n})\n\n/** Select an example locally and sync the choice across the document */\nconst selectExample = (key: string) => {\n localExampleKey.value = key\n eventBus.emit('workspace:update:selected-example', key)\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/**\n * Accessible name for the client picker.\n *\n * On its own the button reads as its current value (\"C Libcurl\"), which never\n * says what activating it does. The visible title stays part of the name so it\n * still matches what is on screen.\n */\nconst clientPickerAriaLabel = computed(() =>\n [clientPickerLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\n/**\n * Accessible name for the focusable code sample, e.g. \"Code sample: Shell cURL\".\n *\n * Screen readers announce only the name and role when focus lands on the scroller, so the\n * name tells the user both what the region is and which client it is generated for.\n */\nconst codeSampleAriaLabel = computed(() =>\n [codeSampleLabel, localSelectedClient.value?.title]\n .filter(Boolean)\n .join(': '),\n)\n\nconst elem = ref<ComponentPublicInstance | null>(null)\nconst visible = useExampleVisibility(elem)\nconst externalExamples = useExternalExamples(\n () =>\n getOperationExamples(operation, localExampleKey.value, selectedContentType),\n () => visible.value,\n)\nconst resolvedOperation = computed(() =>\n resolveOperationExamples(\n operation,\n localExampleKey.value,\n selectedContentType,\n externalExamples.resolve,\n ),\n)\n\n/** Keep the picker available because it also selects the example opened by Test Request. */\nconst showExamplePicker = computed(\n () => Object.keys(requestBodyExamples.value).length > 1,\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: resolvedOperation.value,\n method,\n path,\n example: localExampleKey.value,\n openapiVersion,\n requestBodyCompositionSelection,\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\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 | null>(() => {\n if (isWebhook) {\n return webhookHar.value?.postData?.text ?? ''\n }\n\n return generateCodeSnippet({\n // Only required parameters are shown in code examples; optional parameters\n // are omitted unless explicitly enabled via `x-disabled: false`.\n defaultDisabledParameters: true,\n includeDefaultHeaders: integration === 'client',\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation: resolvedOperation.value,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: localExampleKey.value,\n globalCookies,\n openapiVersion,\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/** 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=\"\n generatedCode === null || generatedCode || externalExamples.pending.value\n \"\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 :inputLabel=\"clientSearchLabel\"\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n teleport\n @update:modelValue=\"selectClient($event as ClientOption)\">\n <ScalarButton\n :aria-label=\"clientPickerAriaLabel\"\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 v-if=\"externalExamples.pending.value\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamples.failed.value\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"externalExamples.retry\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n <div\n v-else-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ codeSampleUnavailable }}\n </div>\n <div\n v-else\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 :label=\"codeSampleAriaLabel\"\n :lang=\"codeBlockLanguage\"\n lineNumbers />\n <ScalarVirtualText\n v-else\n aria-label=\"Request code sample\"\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 role=\"region\"\n :text=\"generatedCode\" />\n </div>\n </ScalarCardSection>\n\n <!-- Footer -->\n <ScalarCardFooter\n v-if=\"showExamplePicker || $slots.footer\"\n class=\"request-card-footer bg-b-3\">\n <!-- Example picker -->\n <div\n v-if=\"showExamplePicker\"\n class=\"request-card-footer-addon\">\n <template v-if=\"Object.keys(requestBodyExamples).length\">\n <ExamplePicker\n :examples=\"requestBodyExamples\"\n :modelValue=\"localExampleKey\"\n @update:modelValue=\"selectExample\" />\n </template>\n </div>\n\n <!-- Footer -->\n <slot\n :exampleName=\"localExampleKey\"\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=\"localExampleKey\"\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 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 +1 @@
1
- {"version":3,"file":"operation-to-har.d.ts","sourceRoot":"","sources":["../../../../src/code-example/helpers/operation-to-har/operation-to-har.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,0BAA0B,EAIhC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AACjH,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,YAAY,CAAA;AASvD,MAAM,MAAM,mBAAmB,GAAG;IAChC,+BAA+B;IAC/B,SAAS,EAAE,eAAe,CAAA;IAC1B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,0BAA0B,EAAE,CAAA;IAC9C,mCAAmC;IACnC,aAAa,CAAC,EAAE,aAAa,EAAE,CAAA;IAC/B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;OAGG;IACH,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,GAAI,+LAa5B,mBAAmB,KAAG,UAyJxB,CAAA"}
1
+ {"version":3,"file":"operation-to-har.d.ts","sourceRoot":"","sources":["../../../../src/code-example/helpers/operation-to-har/operation-to-har.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,0BAA0B,EAIhC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAA;AACxG,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAA;AACjH,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,YAAY,CAAA;AASvD,MAAM,MAAM,mBAAmB,GAAG;IAChC,+BAA+B;IAC/B,SAAS,EAAE,eAAe,CAAA;IAC1B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,0BAA0B,EAAE,CAAA;IAC9C,mCAAmC;IACnC,aAAa,CAAC,EAAE,aAAa,EAAE,CAAA;IAC/B;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;OAGG;IACH,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;OAGG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAA;CACpC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,GAAI,+LAa5B,mBAAmB,KAAG,UAkKxB,CAAA"}
@@ -82,6 +82,7 @@ var u = ({ includeDefaultHeaders: u = !1, operation: d, contentType: f, method:
82
82
  let e = w.url.indexOf("#"), t = e === -1 ? "" : w.url.slice(e), n = e === -1 ? w.url : w.url.slice(0, e), r = w.queryString.map(({ name: e, value: t }) => `${encodeURIComponent(e)}=${t}`).join("&");
83
83
  w.url = `${n}${n.includes("?") ? "&" : "?"}${r}${t}`, w.queryString = [];
84
84
  }
85
+ w.postData?.mimeType === "multipart/form-data" && w.postData.params?.some((e) => e.fileName !== void 0) && (w.headers = w.headers.filter((e) => e.name.toLowerCase() !== "content-type"));
85
86
  let A = 0;
86
87
  for (let e of w.headers) A += (e.name?.length ?? 0) + 2 + (e.value?.length ?? 0) + 2;
87
88
  return w.headersSize = A, w;
@@ -1 +1 @@
1
- {"version":3,"file":"operation-to-har.js","names":[],"sources":["../../../../src/code-example/helpers/operation-to-har/operation-to-har.ts"],"sourcesContent":["import { isElectron } from '@scalar/helpers/general/is-electron'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n type SecuritySchemeObjectSecret,\n filterGlobalCookie,\n getDefaultHeaders,\n restoreConventionalDefaultHeaderNames,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type { OperationObject, ServerObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { Request as HarRequest } from 'har-format'\n\nimport { APP_VERSION } from '@/constants'\n\nimport { processBody } from './process-body'\nimport { processParameters } from './process-parameters'\nimport { processSecuritySchemes } from './process-security-schemes'\nimport { processServerUrl } from './process-server-url'\n\nexport type OperationToHarProps = {\n /** OpenAPI Operation object */\n operation: OperationObject\n /** HTTP method of the operation */\n method: string\n /** Path of the operation */\n path: string\n /**\n * Name of the currently selected operation example\n *\n * Applies to both the body and the parameters\n */\n example?: string\n /**\n * Content type of the operation\n *\n * Applies to both the body and the parameters (if applicable)\n * @defaults to the first content type in the MediaTypeObject\n */\n contentType?: string\n /** OpenAPI Server object */\n server?: ServerObject | null\n /** OpenAPI SecurityScheme objects which are applicable to the operation */\n securitySchemes?: SecuritySchemeObjectSecret[]\n /** Workspace + document cookies */\n globalCookies?: XScalarCookie[]\n /**\n * Whether to include default headers (e.g., Accept, Content-Type) automatically.\n * If false, default headers will be omitted from the HAR request.\n * @default true\n */\n includeDefaultHeaders?: boolean\n /**\n * Selected oneOf/anyOf variants for nested request body example generation\n * (e.g. from the schema dropdowns in the API reference).\n */\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Whether to disable parameters by default.\n * @default false\n */\n defaultDisabledParameters?: boolean\n}\n\n/**\n * Converts an OpenAPI Operation to a HarRequest format for generating HTTP request snippets.\n *\n * This function transforms OpenAPI 3.1 operation objects into HAR (HTTP Archive) format requests,\n * which can be used to generate code snippets for various programming languages and HTTP clients.\n *\n * The conversion handles:\n * - Server URL processing and path parameter substitution\n * - Query parameter formatting based on OpenAPI parameter styles\n * - Request body processing with content type handling\n * - Security scheme integration (API keys, etc.)\n *\n * The resulting HarRequest object follows the HAR specification and includes:\n * - HTTP method and URL\n * - Headers and query parameters\n * - Request body (if present)\n * - Cookie information\n * - Size calculations for headers and body\n *\n * @see https://w3c.github.io/web-performance/specs/HAR/Overview.html\n * @see https://spec.openapis.org/oas/v3.1.0#operation-object\n */\nexport const operationToHar = ({\n includeDefaultHeaders = false,\n operation,\n contentType,\n method,\n path,\n server = null,\n example,\n securitySchemes,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n defaultDisabledParameters = false,\n}: OperationToHarProps): HarRequest => {\n const defaultHeaders = includeDefaultHeaders\n ? getDefaultHeaders({\n method,\n operation,\n exampleName: example ?? 'default',\n hideDisabledHeaders: true,\n hideOverriddenHeaders: true,\n options: { isElectron: isElectron(), appVersion: APP_VERSION },\n })\n : {}\n const defaultHeadersWithConventionalNames = restoreConventionalDefaultHeaderNames(defaultHeaders)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[example ?? 'default'] ?? {}\n\n const serverUrl = processServerUrl(server, path)\n\n // Initialize the HAR request with basic properties\n const harRequest: HarRequest = {\n method,\n url: serverUrl,\n headers: Object.entries(defaultHeadersWithConventionalNames).map(([name, value]) => ({ name, value })),\n queryString: [],\n postData: undefined,\n httpVersion: 'HTTP/1.1',\n cookies: [],\n headersSize: -1,\n bodySize: -1,\n }\n\n let hasCookieStyleEntries = false\n let hasSerializedQuery = false\n\n // Handle parameters\n if (operation.parameters) {\n const {\n url,\n headers,\n queryString,\n cookies,\n hasCookieStyleEntries: processedCookieStyleEntries,\n hasSerializedQuery: processedSerializedQuery,\n } = processParameters({\n harRequest,\n parameters: operation.parameters,\n example,\n defaultDisabled: defaultDisabledParameters,\n })\n\n // Correctly filter the global cookies by the processed url\n const filteredGlobalCookies =\n globalCookies\n ?.filter((cookie) => filterGlobalCookie({ cookie, url, disabledGlobalCookies }))\n ?.map((cookie) => ({ name: cookie.name, value: cookie.value })) ?? []\n\n hasCookieStyleEntries = processedCookieStyleEntries\n hasSerializedQuery = processedSerializedQuery ?? false\n harRequest.url = url\n harRequest.headers = headers\n harRequest.queryString = queryString\n harRequest.cookies = [...filteredGlobalCookies, ...cookies]\n }\n\n const body = getResolvedRef(operation.requestBody)\n\n // Handle request body\n if (body?.content) {\n const postData = processBody({\n requestBody: body,\n contentType,\n example,\n openapiVersion,\n requestBodyCompositionSelection,\n })\n\n if (postData) {\n harRequest.postData = postData\n harRequest.bodySize = postData.text?.length ?? -1\n\n // Add or update Content-Type header\n if (postData.mimeType) {\n const existingContentTypeHeader = harRequest.headers.find(\n (header) => header.name.toLowerCase() === 'content-type',\n )\n // Update existing header if it has an empty value\n if (\n existingContentTypeHeader &&\n (!existingContentTypeHeader.value ||\n (postData.mimeType.startsWith('multipart/') &&\n postData.mimeType.includes('boundary=') &&\n postData.text !== undefined))\n ) {\n existingContentTypeHeader.value = postData.mimeType\n }\n // Add new header if none exists\n else if (!existingContentTypeHeader) {\n harRequest.headers.push({\n name: 'Content-Type',\n value: postData.mimeType,\n })\n }\n }\n }\n }\n\n const hasUriReadyQuery =\n hasSerializedQuery || operation.parameters?.some((parameter) => getResolvedRef(parameter)?.in === 'querystring')\n\n // Handle security schemes\n if (securitySchemes) {\n const { headers, queryString, cookies } = processSecuritySchemes(securitySchemes)\n harRequest.headers.push(...headers)\n // Named parameter values are already serialized, but authentication values are still raw.\n harRequest.queryString.push(\n ...queryString.map((parameter) =>\n hasUriReadyQuery ? { ...parameter, value: encodeURIComponent(parameter.value) } : parameter,\n ),\n )\n harRequest.cookies.push(...cookies)\n }\n\n // Keep authentication and global cookies in the explicit header as well, so\n // snippet generators cannot replace cookie-style parameters with their own header.\n const cookieHeader = harRequest.headers.find((header) => header.name.toLowerCase() === 'cookie')\n if (hasCookieStyleEntries && cookieHeader && harRequest.cookies.length) {\n const extraCookies = harRequest.cookies\n .map((cookie) => `${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`)\n .join('; ')\n cookieHeader.value = cookieHeader.value ? `${cookieHeader.value}; ${extraCookies}` : extraCookies\n harRequest.cookies = []\n }\n\n // Whole-query content and serialized examples must retain their authored URI encoding.\n // Keeping all query data in the URL avoids snippet generators introducing a second question mark.\n if (hasUriReadyQuery && harRequest.queryString.length) {\n const hashIndex = harRequest.url.indexOf('#')\n const hash = hashIndex === -1 ? '' : harRequest.url.slice(hashIndex)\n const url = hashIndex === -1 ? harRequest.url : harRequest.url.slice(0, hashIndex)\n const query = harRequest.queryString.map(({ name, value }) => `${encodeURIComponent(name)}=${value}`).join('&')\n harRequest.url = `${url}${url.includes('?') ? '&' : '?'}${query}${hash}`\n harRequest.queryString = []\n }\n\n // Calculate headers size without allocating a large joined string\n let headersSize = 0\n for (const h of harRequest.headers) {\n // name + \": \" + value + \"\\r\\n\"\n headersSize += (h.name?.length ?? 0) + 2 + (h.value?.length ?? 0) + 2\n }\n harRequest.headersSize = headersSize\n\n return harRequest\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"operation-to-har.js","names":[],"sources":["../../../../src/code-example/helpers/operation-to-har/operation-to-har.ts"],"sourcesContent":["import { isElectron } from '@scalar/helpers/general/is-electron'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport {\n type SecuritySchemeObjectSecret,\n filterGlobalCookie,\n getDefaultHeaders,\n restoreConventionalDefaultHeaderNames,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type { OperationObject, ServerObject } from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { Request as HarRequest } from 'har-format'\n\nimport { APP_VERSION } from '@/constants'\n\nimport { processBody } from './process-body'\nimport { processParameters } from './process-parameters'\nimport { processSecuritySchemes } from './process-security-schemes'\nimport { processServerUrl } from './process-server-url'\n\nexport type OperationToHarProps = {\n /** OpenAPI Operation object */\n operation: OperationObject\n /** HTTP method of the operation */\n method: string\n /** Path of the operation */\n path: string\n /**\n * Name of the currently selected operation example\n *\n * Applies to both the body and the parameters\n */\n example?: string\n /**\n * Content type of the operation\n *\n * Applies to both the body and the parameters (if applicable)\n * @defaults to the first content type in the MediaTypeObject\n */\n contentType?: string\n /** OpenAPI Server object */\n server?: ServerObject | null\n /** OpenAPI SecurityScheme objects which are applicable to the operation */\n securitySchemes?: SecuritySchemeObjectSecret[]\n /** Workspace + document cookies */\n globalCookies?: XScalarCookie[]\n /**\n * Whether to include default headers (e.g., Accept, Content-Type) automatically.\n * If false, default headers will be omitted from the HAR request.\n * @default true\n */\n includeDefaultHeaders?: boolean\n /**\n * Selected oneOf/anyOf variants for nested request body example generation\n * (e.g. from the schema dropdowns in the API reference).\n */\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Whether to disable parameters by default.\n * @default false\n */\n defaultDisabledParameters?: boolean\n}\n\n/**\n * Converts an OpenAPI Operation to a HarRequest format for generating HTTP request snippets.\n *\n * This function transforms OpenAPI 3.1 operation objects into HAR (HTTP Archive) format requests,\n * which can be used to generate code snippets for various programming languages and HTTP clients.\n *\n * The conversion handles:\n * - Server URL processing and path parameter substitution\n * - Query parameter formatting based on OpenAPI parameter styles\n * - Request body processing with content type handling\n * - Security scheme integration (API keys, etc.)\n *\n * The resulting HarRequest object follows the HAR specification and includes:\n * - HTTP method and URL\n * - Headers and query parameters\n * - Request body (if present)\n * - Cookie information\n * - Size calculations for headers and body\n *\n * @see https://w3c.github.io/web-performance/specs/HAR/Overview.html\n * @see https://spec.openapis.org/oas/v3.1.0#operation-object\n */\nexport const operationToHar = ({\n includeDefaultHeaders = false,\n operation,\n contentType,\n method,\n path,\n server = null,\n example,\n securitySchemes,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n defaultDisabledParameters = false,\n}: OperationToHarProps): HarRequest => {\n const defaultHeaders = includeDefaultHeaders\n ? getDefaultHeaders({\n method,\n operation,\n exampleName: example ?? 'default',\n hideDisabledHeaders: true,\n hideOverriddenHeaders: true,\n options: { isElectron: isElectron(), appVersion: APP_VERSION },\n })\n : {}\n const defaultHeadersWithConventionalNames = restoreConventionalDefaultHeaderNames(defaultHeaders)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[example ?? 'default'] ?? {}\n\n const serverUrl = processServerUrl(server, path)\n\n // Initialize the HAR request with basic properties\n const harRequest: HarRequest = {\n method,\n url: serverUrl,\n headers: Object.entries(defaultHeadersWithConventionalNames).map(([name, value]) => ({ name, value })),\n queryString: [],\n postData: undefined,\n httpVersion: 'HTTP/1.1',\n cookies: [],\n headersSize: -1,\n bodySize: -1,\n }\n\n let hasCookieStyleEntries = false\n let hasSerializedQuery = false\n\n // Handle parameters\n if (operation.parameters) {\n const {\n url,\n headers,\n queryString,\n cookies,\n hasCookieStyleEntries: processedCookieStyleEntries,\n hasSerializedQuery: processedSerializedQuery,\n } = processParameters({\n harRequest,\n parameters: operation.parameters,\n example,\n defaultDisabled: defaultDisabledParameters,\n })\n\n // Correctly filter the global cookies by the processed url\n const filteredGlobalCookies =\n globalCookies\n ?.filter((cookie) => filterGlobalCookie({ cookie, url, disabledGlobalCookies }))\n ?.map((cookie) => ({ name: cookie.name, value: cookie.value })) ?? []\n\n hasCookieStyleEntries = processedCookieStyleEntries\n hasSerializedQuery = processedSerializedQuery ?? false\n harRequest.url = url\n harRequest.headers = headers\n harRequest.queryString = queryString\n harRequest.cookies = [...filteredGlobalCookies, ...cookies]\n }\n\n const body = getResolvedRef(operation.requestBody)\n\n // Handle request body\n if (body?.content) {\n const postData = processBody({\n requestBody: body,\n contentType,\n example,\n openapiVersion,\n requestBodyCompositionSelection,\n })\n\n if (postData) {\n harRequest.postData = postData\n harRequest.bodySize = postData.text?.length ?? -1\n\n // Add or update Content-Type header\n if (postData.mimeType) {\n const existingContentTypeHeader = harRequest.headers.find(\n (header) => header.name.toLowerCase() === 'content-type',\n )\n // Update existing header if it has an empty value\n if (\n existingContentTypeHeader &&\n (!existingContentTypeHeader.value ||\n (postData.mimeType.startsWith('multipart/') &&\n postData.mimeType.includes('boundary=') &&\n postData.text !== undefined))\n ) {\n existingContentTypeHeader.value = postData.mimeType\n }\n // Add new header if none exists\n else if (!existingContentTypeHeader) {\n harRequest.headers.push({\n name: 'Content-Type',\n value: postData.mimeType,\n })\n }\n }\n }\n }\n\n const hasUriReadyQuery =\n hasSerializedQuery || operation.parameters?.some((parameter) => getResolvedRef(parameter)?.in === 'querystring')\n\n // Handle security schemes\n if (securitySchemes) {\n const { headers, queryString, cookies } = processSecuritySchemes(securitySchemes)\n harRequest.headers.push(...headers)\n // Named parameter values are already serialized, but authentication values are still raw.\n harRequest.queryString.push(\n ...queryString.map((parameter) =>\n hasUriReadyQuery ? { ...parameter, value: encodeURIComponent(parameter.value) } : parameter,\n ),\n )\n harRequest.cookies.push(...cookies)\n }\n\n // Keep authentication and global cookies in the explicit header as well, so\n // snippet generators cannot replace cookie-style parameters with their own header.\n const cookieHeader = harRequest.headers.find((header) => header.name.toLowerCase() === 'cookie')\n if (hasCookieStyleEntries && cookieHeader && harRequest.cookies.length) {\n const extraCookies = harRequest.cookies\n .map((cookie) => `${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`)\n .join('; ')\n cookieHeader.value = cookieHeader.value ? `${cookieHeader.value}; ${extraCookies}` : extraCookies\n harRequest.cookies = []\n }\n\n // Whole-query content and serialized examples must retain their authored URI encoding.\n // Keeping all query data in the URL avoids snippet generators introducing a second question mark.\n if (hasUriReadyQuery && harRequest.queryString.length) {\n const hashIndex = harRequest.url.indexOf('#')\n const hash = hashIndex === -1 ? '' : harRequest.url.slice(hashIndex)\n const url = hashIndex === -1 ? harRequest.url : harRequest.url.slice(0, hashIndex)\n const query = harRequest.queryString.map(({ name, value }) => `${encodeURIComponent(name)}=${value}`).join('&')\n harRequest.url = `${url}${url.includes('?') ? '&' : '?'}${query}${hash}`\n harRequest.queryString = []\n }\n\n // Multipart file parts are encoded by the HTTP client, which owns the boundary.\n // Raw multipart text already has its boundary and must retain its Content-Type.\n if (\n harRequest.postData?.mimeType === 'multipart/form-data' &&\n harRequest.postData.params?.some((param) => param.fileName !== undefined)\n ) {\n harRequest.headers = harRequest.headers.filter((header) => header.name.toLowerCase() !== 'content-type')\n }\n\n // Calculate headers size without allocating a large joined string\n let headersSize = 0\n for (const h of harRequest.headers) {\n // name + \": \" + value + \"\\r\\n\"\n headersSize += (h.name?.length ?? 0) + 2 + (h.value?.length ?? 0) + 2\n }\n harRequest.headersSize = headersSize\n\n return harRequest\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"process-body.d.ts","sourceRoot":"","sources":["../../../../src/code-example/helpers/operation-to-har/process-body.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAS,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,KAAK,gBAAgB,GAAG,IAAI,CAC1B,mBAAmB,EACnB,aAAa,GAAG,SAAS,GAAG,iCAAiC,GAAG,gBAAgB,CACjF,GAAG;IACF,WAAW,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AA8JD;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,yFAMzB,gBAAgB,KAAG,QAAQ,GAAG,SA0HhC,CAAA"}
1
+ {"version":3,"file":"process-body.d.ts","sourceRoot":"","sources":["../../../../src/code-example/helpers/operation-to-har/process-body.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AACrE,OAAO,KAAK,EAAS,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAE7D,KAAK,gBAAgB,GAAG,IAAI,CAC1B,mBAAmB,EACnB,aAAa,GAAG,SAAS,GAAG,iCAAiC,GAAG,gBAAgB,CACjF,GAAG;IACF,WAAW,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AA0LD;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,yFAMzB,gBAAgB,KAAG,QAAQ,GAAG,SAiIhC,CAAA"}