1
- import { HighlightedCode } from "codehike/code" ;
1
+ import { HighlightedCode } from "codehike/code" ;
2
2
import React from "react" ;
3
- import { SpeakeasyCodeSamplesCore } from "../core.js" ;
4
- import { codeSamplesGet } from "../funcs/codeSamplesGet.js" ;
5
- import { UsageSnippet } from "../models/components/usagesnippet.js" ;
6
- import { GetCodeSamplesRequest } from "../models/operations/getcodesamples.js" ;
7
- import { useSpeakeasyCodeSamplesContext } from "../react-query/_context.js" ;
8
- import { highlightCode } from "./utils.js" ;
3
+ import { SpeakeasyCodeSamplesCore } from "../core.js" ;
4
+ import { codeSamplesGet } from "../funcs/codeSamplesGet.js" ;
5
+ import { UsageSnippet } from "../models/components/usagesnippet.js" ;
6
+ import { GetCodeSamplesRequest } from "../models/operations/getcodesamples.js" ;
7
+ import { useSpeakeasyCodeSamplesContext } from "../react-query/_context.js" ;
8
+ import { highlightCode } from "./utils.js" ;
9
9
10
10
export type SpeakeasyHighlightedCode = HighlightedCode & {
11
11
/** The snippet data from the code samples api */
@@ -15,23 +15,23 @@ export type SpeakeasyHighlightedCode = HighlightedCode & {
15
15
// Define the state shape.
16
16
export type CodeSampleState =
17
17
| {
18
- status : "loading" ;
19
- error ?: Error | undefined ;
20
- snippets ?: SpeakeasyHighlightedCode [ ] | undefined ;
21
- selectedSnippet ?: SpeakeasyHighlightedCode | undefined ;
22
- }
18
+ status : "loading" ;
19
+ error ?: Error | undefined ;
20
+ snippets ?: SpeakeasyHighlightedCode [ ] | undefined ;
21
+ selectedSnippet ?: SpeakeasyHighlightedCode | undefined ;
22
+ }
23
23
| {
24
- status : "success" ;
25
- error ?: Error | undefined ;
26
- snippets : SpeakeasyHighlightedCode [ ] ;
27
- selectedSnippet : SpeakeasyHighlightedCode ;
28
- }
24
+ status : "success" ;
25
+ error ?: Error | undefined ;
26
+ snippets : SpeakeasyHighlightedCode [ ] ;
27
+ selectedSnippet : SpeakeasyHighlightedCode ;
28
+ }
29
29
| {
30
- status : "error" ;
31
- error : Error ;
32
- snippets ?: SpeakeasyHighlightedCode [ ] | undefined ;
33
- selectedSnippet ?: SpeakeasyHighlightedCode | undefined ;
34
- } ;
30
+ status : "error" ;
31
+ error : Error ;
32
+ snippets ?: SpeakeasyHighlightedCode [ ] | undefined ;
33
+ selectedSnippet ?: SpeakeasyHighlightedCode | undefined ;
34
+ } ;
35
35
36
36
type FetchSuccessPayload = {
37
37
snippets : SpeakeasyHighlightedCode [ ] ;
@@ -43,21 +43,27 @@ type Action =
43
43
| { type : "FETCH_INIT" }
44
44
| { type : "FETCH_SUCCESS" ; payload : FetchSuccessPayload }
45
45
| { type : "FETCH_FAILURE" ; payload : Error }
46
- | { type : "SET_LANGUAGE " ; payload : string } ;
46
+ | { type : "SELECT " ; payload : SafeGetSnippetParams }
47
47
48
- function safeGetSnippetForLanguage (
48
+
49
+ type SafeGetSnippetParams = {
50
+ operationId ?: string | undefined ;
51
+ language ?: string | undefined ;
52
+ } ;
53
+
54
+ function safeGetSnippet (
49
55
snippets : SpeakeasyHighlightedCode [ ] ,
50
- language ?: string ,
56
+ { operationId , language} : SafeGetSnippetParams ,
51
57
) : SpeakeasyHighlightedCode {
52
- if ( ! language ) return snippets [ 0 ] ! ;
58
+ const maybeEqual = ( a : string , b : string | undefined ) => b === undefined || a . toLowerCase ( ) === b . toLowerCase ( ) ;
53
59
54
- const selectedSnippet = snippets . find ( ( s ) => s . lang === language ) ;
60
+ const selectedSnippet = snippets . find ( ( s ) => maybeEqual ( s . raw . operationId , operationId ) && maybeEqual ( s . lang , language ) ) ;
55
61
if ( selectedSnippet ) {
56
62
return selectedSnippet ;
57
63
}
58
64
59
65
console . warn (
60
- `Could not find snippet for language "${ language } ".` ,
66
+ `Could not find snippet for operationId "${ operationId } ".` ,
61
67
`Falling back to to first language in snippet array.` ,
62
68
) ;
63
69
@@ -70,14 +76,14 @@ const reducer: React.Reducer<CodeSampleState, Action> = (
70
76
) => {
71
77
switch ( action . type ) {
72
78
case "FETCH_INIT" :
73
- return { ...state , status : "loading" } ;
79
+ return { ...state , status : "loading" } ;
74
80
case "FETCH_SUCCESS" :
75
81
return {
76
82
status : "success" ,
77
83
snippets : action . payload . snippets ,
78
- selectedSnippet : safeGetSnippetForLanguage (
84
+ selectedSnippet : safeGetSnippet (
79
85
action . payload . snippets ,
80
- action . payload . defaultLanguage ,
86
+ { language : action . payload . defaultLanguage } ,
81
87
) ,
82
88
} ;
83
89
case "FETCH_FAILURE" :
@@ -86,10 +92,10 @@ const reducer: React.Reducer<CodeSampleState, Action> = (
86
92
status : "error" ,
87
93
error : action . payload ,
88
94
} ;
89
- case "SET_LANGUAGE " :
95
+ case "SELECT " :
90
96
return {
91
97
...state ,
92
- selectedSnippet : safeGetSnippetForLanguage (
98
+ selectedSnippet : safeGetSnippet (
93
99
state . snippets ! ,
94
100
action . payload ,
95
101
) ,
@@ -106,11 +112,11 @@ type UseCodeSampleStateInit = {
106
112
} ;
107
113
108
114
export const useCodeSampleState = ( {
109
- client : clientProp ,
110
- requestParams,
111
- defaultLanguage,
112
- } : UseCodeSampleStateInit ) => {
113
- const [ state , dispatch ] = React . useReducer ( reducer , { status : "loading" } ) ;
115
+ client : clientProp ,
116
+ requestParams,
117
+ defaultLanguage,
118
+ } : UseCodeSampleStateInit ) => {
119
+ const [ state , dispatch ] = React . useReducer ( reducer , { status : "loading" } ) ;
114
120
const client = useSafeSpeakeasyCodeSamplesContext ( clientProp ) ;
115
121
116
122
const highlightSnippets = async ( snippets : UsageSnippet [ ] ) => {
@@ -122,17 +128,17 @@ export const useCodeSampleState = ({
122
128
"github-from-css" ,
123
129
) ;
124
130
125
- return { ...highlightedCode , raw : snippet } ;
131
+ return { ...highlightedCode , raw : snippet } ;
126
132
} ) ,
127
133
) ;
128
134
} ;
129
135
130
136
async function handleMount ( ) {
131
- dispatch ( { type : "FETCH_INIT" } ) ;
137
+ dispatch ( { type : "FETCH_INIT" } ) ;
132
138
const result = await codeSamplesGet ( client , requestParams ) ;
133
139
134
140
if ( ! result . ok ) {
135
- return dispatch ( { type : "FETCH_FAILURE" , payload : result . error } ) ;
141
+ return dispatch ( { type : "FETCH_FAILURE" , payload : result . error } ) ;
136
142
}
137
143
138
144
dispatch ( {
@@ -148,11 +154,17 @@ export const useCodeSampleState = ({
148
154
handleMount ( ) ;
149
155
} , [ ] ) ;
150
156
151
- function setSelectedLanguage ( language : string ) {
152
- dispatch ( { type : "SET_LANGUAGE" , payload : language } ) ;
157
+ function selectSnippet ( params : SafeGetSnippetParams ) {
158
+ dispatch ( {
159
+ type : "SELECT" , payload : {
160
+ language : state . selectedSnippet ?. raw . language ,
161
+ operationId : state . selectedSnippet ?. raw . operationId ,
162
+ ...params ,
163
+ }
164
+ } ) ;
153
165
}
154
166
155
- return { state, setSelectedLanguage } ;
167
+ return { state, selectSnippet } ;
156
168
} ;
157
169
158
170
/** Intended to give the user the option of providing their own client. */
@@ -169,7 +181,7 @@ export const useSafeSpeakeasyCodeSamplesContext = (
169
181
} catch {
170
182
throw new Error (
171
183
"The Speakeasy Code Samples component must either be given an apiKey and " +
172
- "registryUrl, or be wrapped in a SpeakeasyCodeSamplesProvider." ,
184
+ "registryUrl, or be wrapped in a SpeakeasyCodeSamplesProvider." ,
173
185
) ;
174
186
}
175
187
} ;
0 commit comments