@@ -31,7 +31,7 @@ async function main(): Promise<void> {
3131 ] )
3232}
3333
34- const openapiResponseKeyProp = 'x-fern-sdk-return-value '
34+ const openapiResponseKeyProp = 'x-response-key '
3535
3636const routePaths = [
3737 '/access_codes' ,
@@ -124,9 +124,9 @@ interface ClassMeta {
124124}
125125
126126const createRoutes = ( ) : Route [ ] => {
127- const paths = Object . keys ( openapi . paths )
127+ const allOpenapiPaths = Object . keys ( openapi . paths )
128128
129- const unmatchedEndpointPaths = paths
129+ const unmatchedEndpointPaths = allOpenapiPaths
130130 . filter (
131131 ( path ) =>
132132 ! routePaths . some ( ( routePath ) => isEndpointUnderRoute ( path , routePath ) ) ,
@@ -141,19 +141,42 @@ const createRoutes = (): Route[] => {
141141 )
142142 }
143143
144- return routePaths . map ( createRoute )
145- }
144+ const routesToGenerate = routePaths . filter (
145+ ( routePath ) =>
146+ hasAtLeastOneDocumentedEndpoint ( routePath ) || isNamespaceRoute ( routePath ) ,
147+ )
146148
147- const createRoute = ( routePath : ( typeof routePaths ) [ number ] ) : Route => {
148- const endpointPaths = Object . keys ( openapi . paths ) . filter ( ( path ) =>
149- isEndpointUnderRoute ( path , routePath ) ,
149+ return routesToGenerate . map ( ( routePath ) =>
150+ createRoute ( routePath , routesToGenerate ) ,
150151 )
152+ }
153+
154+ const createRoute = (
155+ routePath : ( typeof routePaths ) [ number ] ,
156+ documentedRoutePaths : ReadonlyArray < ( typeof routePaths ) [ number ] > ,
157+ ) : Route => {
158+ const endpointPaths = Object . entries ( openapi . paths )
159+ . filter ( ( [ path , pathSchema ] ) => {
160+ if ( ! isEndpointUnderRoute ( path , routePath ) ) {
161+ return false
162+ }
163+
164+ return 'post' in pathSchema && ! ( 'x-undocumented' in pathSchema . post )
165+ } )
166+ . map ( ( [ path ] ) => path )
151167
152168 const namespace = routePath . split ( '/' ) . join ( '_' ) . slice ( 1 )
153169
170+ const subresources = ( routePathSubresources [ routePath ] ?? [ ] ) . filter (
171+ ( subresource ) => {
172+ const subresourcePath = `${ routePath } /${ subresource } `
173+ return documentedRoutePaths . some ( ( path ) => path === subresourcePath )
174+ } ,
175+ )
176+
154177 return {
155178 namespace,
156- subresources : routePathSubresources [ routePath ] ?? [ ] ,
179+ subresources,
157180 endpoints : endpointPaths . map ( ( endpointPath ) =>
158181 createEndpoint ( namespace , routePath , endpointPath ) ,
159182 ) ,
@@ -245,6 +268,46 @@ const isEndpointUnderRoute = (
245268 endpointPath . startsWith ( routePath ) &&
246269 endpointPath . split ( '/' ) . length - 1 === routePath . split ( '/' ) . length
247270
271+ const hasAtLeastOneDocumentedEndpoint = (
272+ routePath : ( typeof routePaths ) [ number ] ,
273+ ) : boolean => {
274+ const endpointsUnderRoute = Object . keys ( openapi . paths ) . filter ( ( path ) =>
275+ isEndpointUnderRoute ( path , routePath ) ,
276+ )
277+
278+ if ( endpointsUnderRoute . length === 0 ) {
279+ return false
280+ }
281+
282+ return endpointsUnderRoute . some ( ( path ) => {
283+ if ( ! isOpenapiPath ( path ) ) return false
284+
285+ const pathSchema = openapi . paths [ path ]
286+ if ( ! ( 'post' in pathSchema ) ) return false
287+
288+ return ! ( 'x-undocumented' in pathSchema . post )
289+ } )
290+ }
291+
292+ /**
293+ * Determines if a route is a namespace route by checking if it has defined subresources
294+ * and if any of those subresources have corresponding route paths.
295+ * (e.g., "/acs" which contains "/acs/users", "/acs/systems", etc.)
296+ * These routes should be generated even if they don't have direct endpoints themselves.
297+ */
298+ function isNamespaceRoute ( routePath : ( typeof routePaths ) [ number ] ) : boolean {
299+ const subresources = routePathSubresources [ routePath ] ?? [ ]
300+ if ( subresources . length === 0 ) {
301+ return false
302+ }
303+
304+ return subresources . some ( ( subresource ) => {
305+ const subresourcePath =
306+ `${ routePath } /${ subresource } ` as ( typeof routePaths ) [ number ]
307+ return routePaths . includes ( subresourcePath )
308+ } )
309+ }
310+
248311const renderRoute = ( route : Route , { constructors } : ClassMeta ) : string => `
249312/*
250313* Automatically generated by generate-routes.ts.
@@ -386,9 +449,7 @@ const renderClassMethodOptions = ({
386449 resource,
387450} : Pick < Endpoint , 'resource' > ) : string => {
388451 if ( resource === 'action_attempt' ) {
389- return `options: ${ renderClassMethodOptionsTypeDef ( {
390- resource,
391- } ) } = {},`
452+ return `options: ${ renderClassMethodOptionsTypeDef ( { resource } ) } = {},`
392453 }
393454 return ''
394455}
0 commit comments