11import { z } from 'zod'
22
3- import {
4- type CodeSample ,
5- CodeSampleDefinitionSchema ,
6- createCodeSample ,
7- } from './code-sample/index.js'
8- import type {
9- CodeSampleDefinition ,
10- CodeSampleSyntax ,
11- } from './code-sample/schema.js'
123import { findCommonOpenapiSchemaProperties } from './openapi/find-common-openapi-schema-properties.js'
134import { flattenOpenapiSchema } from './openapi/flatten-openapi-schema.js'
145import {
@@ -26,6 +17,17 @@ import type {
2617 OpenapiPaths ,
2718 OpenapiSchema ,
2819} from './openapi/types.js'
20+ import {
21+ type CodeSample ,
22+ type CodeSampleDefinition ,
23+ CodeSampleDefinitionSchema ,
24+ createCodeSample ,
25+ createResourceSample ,
26+ type ResourceSample ,
27+ type ResourceSampleDefinition ,
28+ ResourceSampleDefinitionSchema ,
29+ type SyntaxName ,
30+ } from './samples/index.js'
2931import {
3032 mapOpenapiToSeamAuthMethod ,
3133 type SeamAuthMethod ,
@@ -66,6 +68,7 @@ export interface Resource {
6668 isDraft : boolean
6769 draftMessage : string
6870 propertyGroups : Record < string , PropertyGroup >
71+ resourceSamples : ResourceSample [ ]
6972}
7073
7174interface PropertyGroup {
@@ -413,11 +416,15 @@ export type Method = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
413416
414417interface Context extends Required < BlueprintOptions > {
415418 codeSampleDefinitions : CodeSampleDefinition [ ]
419+ resourceSampleDefinitions : ResourceSampleDefinition [ ]
416420 validActionAttemptTypes : string [ ]
417421}
418422
419423export const TypesModuleSchema = z . object ( {
420424 codeSampleDefinitions : z . array ( CodeSampleDefinitionSchema ) . default ( [ ] ) ,
425+ resourceSampleDefinitions : z
426+ . array ( ResourceSampleDefinitionSchema )
427+ . default ( [ ] ) ,
421428 // TODO: Import and use openapi zod schema here
422429 openapi : z . any ( ) ,
423430} )
@@ -427,14 +434,15 @@ export type TypesModuleInput = z.input<typeof TypesModuleSchema>
427434export type TypesModule = z . output < typeof TypesModuleSchema >
428435
429436export interface BlueprintOptions {
430- formatCode ?: ( content : string , syntax : CodeSampleSyntax ) => Promise < string >
437+ formatCode ?: ( content : string , syntax : SyntaxName ) => Promise < string >
431438}
432439
433440export const createBlueprint = async (
434441 typesModule : TypesModuleInput ,
435442 { formatCode = async ( content ) => content } : BlueprintOptions = { } ,
436443) : Promise < Blueprint > => {
437- const { codeSampleDefinitions } = TypesModuleSchema . parse ( typesModule )
444+ const { codeSampleDefinitions, resourceSampleDefinitions } =
445+ TypesModuleSchema . parse ( typesModule )
438446
439447 // TODO: Move openapi to TypesModuleSchema
440448 const openapi = typesModule . openapi as Openapi
@@ -445,6 +453,7 @@ export const createBlueprint = async (
445453
446454 const context : Context = {
447455 codeSampleDefinitions,
456+ resourceSampleDefinitions,
448457 formatCode,
449458 validActionAttemptTypes,
450459 }
@@ -458,18 +467,19 @@ export const createBlueprint = async (
458467 ) ,
459468 )
460469
461- const resources = createResources ( openapiSchemas , routes )
462- const actionAttempts = createActionAttempts (
470+ const resources = await createResources ( openapiSchemas , routes , context )
471+ const actionAttempts = await createActionAttempts (
463472 openapi . components . schemas ,
464473 routes ,
474+ context ,
465475 )
466476
467477 return {
468478 title : openapi . info . title ,
469479 routes,
470480 resources,
471481 pagination : createPagination ( pagination ) ,
472- events : createEvents ( openapiSchemas , resources , routes ) ,
482+ events : await createEvents ( openapiSchemas , resources , routes , context ) ,
473483 actionAttempts,
474484 }
475485}
@@ -1074,59 +1084,66 @@ const createPagination = (
10741084 }
10751085}
10761086
1077- export const createResources = (
1087+ export const createResources = async (
10781088 schemas : Openapi [ 'components' ] [ 'schemas' ] ,
10791089 routes : Route [ ] ,
1080- ) : Record < string , Resource > => {
1081- return Object . entries ( schemas ) . reduce < Record < string , Resource > > (
1082- ( resources , [ schemaName , schema ] ) => {
1083- const { success : isValidEventSchema , data : parsedEvent } =
1084- EventResourceSchema . safeParse ( schema )
1085- if ( isValidEventSchema ) {
1086- const commonProperties = findCommonOpenapiSchemaProperties (
1087- parsedEvent . oneOf ,
1088- )
1089- const eventSchema : OpenapiSchema = {
1090- 'x-route-path' : parsedEvent [ 'x-route-path' ] ,
1091- properties : commonProperties ,
1092- type : 'object' ,
1093- }
1094- return {
1095- ...resources ,
1096- [ schemaName ] : createResource ( schemaName , eventSchema , routes ) ,
1097- }
1090+ context : Context ,
1091+ ) : Promise < Record < string , Resource > > => {
1092+ const resources : Record < string , Resource > = { }
1093+ for ( const [ schemaName , schema ] of Object . entries ( schemas ) ) {
1094+ const { success : isValidEventSchema , data : parsedEvent } =
1095+ EventResourceSchema . safeParse ( schema )
1096+
1097+ if ( isValidEventSchema ) {
1098+ const commonProperties = findCommonOpenapiSchemaProperties (
1099+ parsedEvent . oneOf ,
1100+ )
1101+ const eventSchema : OpenapiSchema = {
1102+ 'x-route-path' : parsedEvent [ 'x-route-path' ] ,
1103+ properties : commonProperties ,
1104+ type : 'object' ,
10981105 }
1106+ resources [ schemaName ] = await createResource (
1107+ schemaName ,
1108+ eventSchema ,
1109+ routes ,
1110+ context ,
1111+ )
1112+ continue
1113+ }
10991114
1100- const { success : isValidResourceSchema } =
1101- ResourceSchema . safeParse ( schema )
1102- if ( isValidResourceSchema ) {
1103- return {
1104- ...resources ,
1105- [ schemaName ] : createResource ( schemaName , schema , routes ) ,
1106- }
1107- }
1115+ const { success : isValidResourceSchema } = ResourceSchema . safeParse ( schema )
1116+ if ( isValidResourceSchema ) {
1117+ resources [ schemaName ] = await createResource (
1118+ schemaName ,
1119+ schema ,
1120+ routes ,
1121+ context ,
1122+ )
1123+ continue
1124+ }
1125+ }
11081126
1109- return resources
1110- } ,
1111- { } ,
1112- )
1127+ return resources
11131128}
11141129
1115- const createResource = (
1130+ const createResource = async (
11161131 schemaName : string ,
11171132 schema : OpenapiSchema ,
11181133 routes : Route [ ] ,
1119- ) : Resource => {
1134+ context : Context ,
1135+ ) : Promise < Resource > => {
11201136 const routePath = validateRoutePath (
11211137 schemaName ,
11221138 schema [ 'x-route-path' ] ,
11231139 routes ,
11241140 )
11251141
11261142 const propertyGroups = getPropertyGroupsForResource ( schema )
1143+ const resourceType = schemaName
11271144
1128- return {
1129- resourceType : schemaName ,
1145+ const resource : Omit < Resource , 'resourceSamples' > = {
1146+ resourceType,
11301147 properties : createProperties (
11311148 schema . properties ?? { } ,
11321149 [ schemaName ] ,
@@ -1142,6 +1159,23 @@ const createResource = (
11421159 draftMessage : schema [ 'x-draft' ] ?? '' ,
11431160 propertyGroups,
11441161 }
1162+
1163+ return {
1164+ ...resource ,
1165+ resourceSamples : await Promise . all (
1166+ context . resourceSampleDefinitions
1167+ . filter (
1168+ ( resourceSample ) => resourceSample . resource_type === resourceType ,
1169+ )
1170+ . map (
1171+ async ( resourceSampleDefinition ) =>
1172+ await createResourceSample ( resourceSampleDefinition , {
1173+ resource,
1174+ formatCode : context . formatCode ,
1175+ } ) ,
1176+ ) ,
1177+ ) ,
1178+ }
11451179}
11461180
11471181const validateRoutePath = (
@@ -1620,11 +1654,12 @@ export const getPreferredMethod = (
16201654 return semanticMethod
16211655}
16221656
1623- const createEvents = (
1657+ const createEvents = async (
16241658 schemas : Openapi [ 'components' ] [ 'schemas' ] ,
16251659 resources : Record < string , Resource > ,
16261660 routes : Route [ ] ,
1627- ) : EventResource [ ] => {
1661+ context : Context ,
1662+ ) : Promise < EventResource [ ] > => {
16281663 const eventSchema = schemas [ 'event' ]
16291664 if (
16301665 eventSchema == null ||
@@ -1635,8 +1670,8 @@ const createEvents = (
16351670 return [ ]
16361671 }
16371672
1638- return eventSchema . oneOf
1639- . map ( ( schema ) => {
1673+ const events = await Promise . all (
1674+ eventSchema . oneOf . map ( async ( schema ) => {
16401675 if (
16411676 typeof schema !== 'object' ||
16421677 schema . properties ?. [ 'event_type' ] ?. enum ?. [ 0 ] == null
@@ -1650,18 +1685,21 @@ const createEvents = (
16501685 )
16511686
16521687 return {
1653- ...createResource ( 'event' , schema , routes ) ,
1688+ ...( await createResource ( 'event' , schema , routes , context ) ) ,
16541689 eventType,
16551690 targetResourceType : targetResourceType ?? null ,
16561691 }
1657- } )
1658- . filter ( ( event ) : event is EventResource => event !== null )
1692+ } ) ,
1693+ )
1694+
1695+ return events . filter ( ( event ) : event is EventResource => event !== null )
16591696}
16601697
1661- const createActionAttempts = (
1698+ const createActionAttempts = async (
16621699 schemas : Openapi [ 'components' ] [ 'schemas' ] ,
16631700 routes : Route [ ] ,
1664- ) : ActionAttempt [ ] => {
1701+ context : Context ,
1702+ ) : Promise < ActionAttempt [ ] > => {
16651703 const actionAttemptSchema = schemas [ 'action_attempt' ]
16661704 if (
16671705 actionAttemptSchema == null ||
@@ -1692,62 +1730,65 @@ const createActionAttempts = (
16921730 }
16931731 }
16941732
1695- return Array . from ( schemasByActionType . entries ( ) ) . map (
1696- ( [ actionType , schemas ] ) => {
1697- const mergedProperties : Record < string , OpenapiSchema > = { }
1698-
1699- const allPropertyKeys = new Set < string > ( )
1700- for ( const schema of schemas ) {
1701- if ( schema . properties != null ) {
1702- Object . keys ( schema . properties ) . forEach ( ( key ) =>
1703- allPropertyKeys . add ( key ) ,
1704- )
1733+ return await Promise . all (
1734+ Array . from ( schemasByActionType . entries ( ) ) . map (
1735+ async ( [ actionType , schemas ] ) => {
1736+ const mergedProperties : Record < string , OpenapiSchema > = { }
1737+
1738+ const allPropertyKeys = new Set < string > ( )
1739+ for ( const schema of schemas ) {
1740+ if ( schema . properties != null ) {
1741+ Object . keys ( schema . properties ) . forEach ( ( key ) =>
1742+ allPropertyKeys . add ( key ) ,
1743+ )
1744+ }
17051745 }
1706- }
17071746
1708- for ( const propKey of allPropertyKeys ) {
1709- const propDefinitions = schemas
1710- . filter ( ( schema ) => schema . properties ?. [ propKey ] != null )
1711- . map ( ( schema ) => schema . properties ?. [ propKey ] )
1747+ for ( const propKey of allPropertyKeys ) {
1748+ const propDefinitions = schemas
1749+ . filter ( ( schema ) => schema . properties ?. [ propKey ] != null )
1750+ . map ( ( schema ) => schema . properties ?. [ propKey ] )
17121751
1713- if ( propDefinitions . length === 0 ) continue
1752+ if ( propDefinitions . length === 0 ) continue
17141753
1715- const nonNullableDefinition = propDefinitions . find ( ( prop ) => {
1716- if ( prop == null ) return false
1754+ const nonNullableDefinition = propDefinitions . find ( ( prop ) => {
1755+ if ( prop == null ) return false
17171756
1718- return ! ( 'nullable' in prop && prop . nullable === true )
1719- } )
1757+ return ! ( 'nullable' in prop && prop . nullable === true )
1758+ } )
17201759
1721- mergedProperties [ propKey ] =
1722- nonNullableDefinition ?? propDefinitions [ 0 ] ?? { }
1723- }
1760+ mergedProperties [ propKey ] =
1761+ nonNullableDefinition ?? propDefinitions [ 0 ] ?? { }
1762+ }
17241763
1725- // Ensure standard status field
1726- mergedProperties [ 'status' ] = {
1727- ...mergedProperties [ 'status' ] ,
1728- type : 'string' ,
1729- enum : [ 'success' , 'pending' , 'error' ] ,
1730- }
1764+ // Ensure standard status field
1765+ mergedProperties [ 'status' ] = {
1766+ ...mergedProperties [ 'status' ] ,
1767+ type : 'string' ,
1768+ enum : [ 'success' , 'pending' , 'error' ] ,
1769+ }
17311770
1732- const schemaWithMergedProperties : OpenapiSchema = {
1733- ...( actionAttemptSchema [ 'x-route-path' ] != null && {
1734- 'x-route-path' : actionAttemptSchema [ 'x-route-path' ] ,
1735- } ) ,
1736- ...schemas [ 0 ] ,
1737- properties : mergedProperties ,
1738- }
1771+ const schemaWithMergedProperties : OpenapiSchema = {
1772+ ...( actionAttemptSchema [ 'x-route-path' ] != null && {
1773+ 'x-route-path' : actionAttemptSchema [ 'x-route-path' ] ,
1774+ } ) ,
1775+ ...schemas [ 0 ] ,
1776+ properties : mergedProperties ,
1777+ }
17391778
1740- const resource = createResource (
1741- 'action_attempt' ,
1742- schemaWithMergedProperties ,
1743- routes ,
1744- )
1779+ const resource = await createResource (
1780+ 'action_attempt' ,
1781+ schemaWithMergedProperties ,
1782+ routes ,
1783+ context ,
1784+ )
17451785
1746- return {
1747- ...resource ,
1748- resourceType : 'action_attempt' ,
1749- actionAttemptType : actionType ,
1750- }
1751- } ,
1786+ return {
1787+ ...resource ,
1788+ resourceType : 'action_attempt' ,
1789+ actionAttemptType : actionType ,
1790+ }
1791+ } ,
1792+ ) ,
17521793 )
17531794}
0 commit comments