1- import type { OpenAPIV3_1 } from '@gitbook/openapi-parser' ;
2- import type React from 'react' ;
3- import { ScalarApiButton } from './ScalarApiButton' ;
1+ import { OpenAPICopyButton } from './OpenAPICopyButton' ;
42import type { OpenAPIContextProps , OpenAPIOperationData } from './types' ;
3+ import { getDefaultServerURL } from './util/server' ;
54
65/**
76 * Display the path of an operation.
@@ -10,63 +9,62 @@ export function OpenAPIPath(props: {
109 data : OpenAPIOperationData ;
1110 context : OpenAPIContextProps ;
1211} ) {
13- const { data, context } = props ;
14- const { method, path } = data ;
15- const { specUrl } = context ;
16- const hideTryItPanel = data [ 'x-hideTryItPanel' ] || data . operation [ 'x-hideTryItPanel' ] ;
12+ const { data } = props ;
13+ const { method, path, operation } = data ;
14+
15+ const server = getDefaultServerURL ( data . servers ) ;
16+ const formattedPath = formatPath ( path ) ;
1717
1818 return (
1919 < div className = "openapi-path" >
2020 < div className = { `openapi-method openapi-method-${ method } ` } > { method } </ div >
21- < div className = "openapi-path-title" data-deprecated = { data . operation . deprecated } >
22- < p > { formatPath ( path ) } </ p >
23- </ div >
24- { ! hideTryItPanel && validateHttpMethod ( method ) && (
25- < ScalarApiButton method = { method } path = { path } specUrl = { specUrl } />
26- ) }
21+
22+ < OpenAPICopyButton
23+ value = { server + path }
24+ className = "openapi-path-title"
25+ data-deprecated = { operation . deprecated }
26+ >
27+ < span className = "openapi-path-server" > { server } </ span >
28+ { formattedPath }
29+ </ OpenAPICopyButton >
2730 </ div >
2831 ) ;
2932}
3033
31- function validateHttpMethod ( method : string ) : method is OpenAPIV3_1 . HttpMethods {
32- return [ 'get' , 'post' , 'put' , 'delete' , 'patch' , 'head' , 'options' , 'trace' ] . includes ( method ) ;
33- }
34-
35- // Format the path to highlight placeholders
34+ /**
35+ * Format the path by wrapping placeholders in <span> tags.
36+ */
3637function formatPath ( path : string ) {
3738 // Matches placeholders like {id}, {userId}, etc.
38- const regex = / \{ ( \w + ) \} / g;
39+ const regex = / \{ \s * ( \w + ) \s * \} | : \w + / g;
3940
4041 const parts : ( string | React . JSX . Element ) [ ] = [ ] ;
4142 let lastIndex = 0 ;
4243
43- // Replace placeholders with <em> tags
44- path . replace ( regex , ( match , key , offset ) => {
45- parts . push ( path . slice ( lastIndex , offset ) ) ;
46- parts . push ( < em key = { key } > { `{${ key } }` } </ em > ) ;
44+ //Wrap the variables in <span> tags and maintain either {variable} or :variable
45+ path . replace ( regex , ( match , _ , offset ) => {
46+ if ( offset > lastIndex ) {
47+ parts . push ( path . slice ( lastIndex , offset ) ) ;
48+ }
49+ parts . push (
50+ < span key = { offset } className = "openapi-path-variable" >
51+ { match }
52+ </ span >
53+ ) ;
4754 lastIndex = offset + match . length ;
4855 return match ;
4956 } ) ;
5057
51- // Push remaining text after the last placeholder
52- parts . push ( path . slice ( lastIndex ) ) ;
53-
54- // Join parts with separators wrapped in <span>
55- const formattedPath = parts . reduce (
56- ( acc , part , index ) => {
57- if ( typeof part === 'string' && index > 0 && part === '/' ) {
58- acc . push (
59- < span className = "openapi-path-separator" key = { `sep-${ index } ` } >
60- /
61- </ span >
62- ) ;
63- }
58+ if ( lastIndex < path . length ) {
59+ parts . push ( path . slice ( lastIndex ) ) ;
60+ }
6461
65- acc . push ( part ) ;
66- return acc ;
67- } ,
68- [ ] as ( string | React . JSX . Element ) [ ]
69- ) ;
62+ const formattedPath = parts . map ( ( part , index ) => {
63+ if ( typeof part === 'string' ) {
64+ return < span key = { index } > { part } </ span > ;
65+ }
66+ return part ;
67+ } ) ;
7068
71- return < span > { formattedPath } </ span > ;
69+ return formattedPath ;
7270}
0 commit comments