@@ -4,7 +4,6 @@ import { resolve } from 'node:path'
4
4
import { openapi } from '@seamapi/types/connect'
5
5
import { camelCase , paramCase , pascalCase , snakeCase } from 'change-case'
6
6
import { ESLint } from 'eslint'
7
- import pluralize from 'pluralize'
8
7
import { format , resolveConfig } from 'prettier'
9
8
10
9
const rootClassPath = resolve ( 'src' , 'lib' , 'seam' , 'connect' , 'client.ts' )
@@ -53,24 +52,14 @@ const endpointResources: Partial<
53
52
| null
54
53
>
55
54
> = {
56
- '/access_codes/generate_code' : 'generated_code' ,
57
- '/access_codes/create_multiple' : 'access_codes' ,
58
- '/access_codes/pull_backup_access_code' : 'backup_access_code' ,
59
- '/access_codes/unmanaged/convert_to_managed' : null ,
60
- '/acs/access_groups/list_users' : 'acs_users' ,
61
- '/acs/access_groups/remove_user' : null ,
62
- '/acs/users/add_to_access_group' : null ,
63
- '/acs/users/remove_from_access_group' : null ,
55
+ '/access_codes/delete' : null ,
56
+ '/access_codes/unmanaged/delete' : null ,
57
+ '/access_codes/update' : null ,
64
58
'/connect_webviews/view' : null ,
65
- '/devices/list_device_providers' : 'device_providers' ,
66
- '/locks/lock_door' : 'action_attempt' ,
67
- '/locks/unlock_door' : 'action_attempt' ,
68
- '/noise_sensors/noise_thresholds/create' : null , // could return action action_attempt
69
- '/thermostats/cool' : null ,
70
- '/thermostats/heat' : null ,
71
- '/thermostats/heat_cool' : null ,
72
- '/thermostats/off' : null ,
73
- '/thermostats/set_fan_mode' : null ,
59
+ '/noise_sensors/noise_thresholds/create' : null ,
60
+ '/noise_sensors/noise_thresholds/delete' : null ,
61
+ '/noise_sensors/noise_thresholds/update' : null ,
62
+ '/thermostats/climate_setting_schedules/update' : null ,
74
63
'/workspaces/reset_sandbox' : null ,
75
64
}
76
65
@@ -88,7 +77,7 @@ interface Endpoint {
88
77
requestFormat : 'params' | 'body'
89
78
}
90
79
91
- type Method = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'
80
+ type Method = 'GET' | 'POST'
92
81
93
82
interface ClassMeta {
94
83
constructors : string
@@ -150,46 +139,48 @@ const createEndpoint = (
150
139
namespace,
151
140
path : endpointPath ,
152
141
method,
153
- resource : deriveResource ( endpointPath , routePath , name , method ) ,
142
+ resource : deriveResource ( endpointPath , method ) ,
154
143
requestFormat : [ 'GET' , 'DELETE' ] . includes ( method ) ? 'params' : 'body' ,
155
144
}
156
145
}
157
146
158
147
const deriveResource = (
159
148
endpointPath : string ,
160
- routePath : string ,
161
- name : string ,
162
149
method : Method ,
163
150
) : string | null => {
164
151
if ( isEndpointResource ( endpointPath ) ) {
165
152
return endpointResources [ endpointPath ] ?? null
166
153
}
167
- if ( [ 'DELETE' , 'PATCH' , 'PUT' ] . includes ( method ) ) return null
168
- if ( [ 'update' , 'delete' ] . includes ( name ) ) return null
169
- const group = deriveGroupFromRoutePath ( routePath )
170
- if ( group == null ) throw new Error ( `Could not parse group from ${ routePath } ` )
171
- if ( name === 'list' ) return group
172
- return pluralize . singular ( group )
173
- }
174
-
175
- const deriveGroupFromRoutePath = ( routePath : string ) : string | undefined => {
176
- const parts = routePath . split ( '/' ) . slice ( 1 )
177
-
178
- if ( routePath . endsWith ( '/unmanaged' ) ) {
179
- return parts [ 0 ]
180
- }
181
-
182
- if ( routePath . startsWith ( '/acs' ) ) {
183
- return [ parts [ 0 ] , parts [ 1 ] ] . join ( '_' )
184
- }
185
154
186
- if ( parts . length === 2 ) {
187
- return parts [ 1 ]
155
+ if ( isOpenApiPath ( endpointPath ) ) {
156
+ const spec = openapi . paths [ endpointPath ]
157
+ const methodKey = method . toLowerCase ( )
158
+
159
+ if ( methodKey === 'post' && 'post' in spec ) {
160
+ const response = spec . post . responses [ 200 ]
161
+ if ( ! ( 'content' in response ) ) return null
162
+ return deriveResourceFromSchema (
163
+ response . content [ 'application/json' ] ?. schema ?. properties ?? { } ,
164
+ )
165
+ }
166
+
167
+ if ( methodKey === 'get' && 'get' in spec ) {
168
+ const response = spec . get . responses [ 200 ]
169
+ if ( ! ( 'content' in response ) ) {
170
+ throw new Error ( `Missing resource for ${ method } ${ endpointPath } ` )
171
+ }
172
+ return deriveResourceFromSchema (
173
+ response . content [ 'application/json' ] ?. schema ?. properties ?? { } ,
174
+ )
175
+ }
188
176
}
189
177
190
- return parts [ 0 ]
178
+ throw new Error ( `Could not derive resource for ${ method } ${ endpointPath } ` )
191
179
}
192
180
181
+ const deriveResourceFromSchema = ( properties : object ) : string | null =>
182
+ Object . keys ( properties ) . filter ( ( key ) => key !== 'ok' ) [ 0 ] ?? null
183
+
193
184
const deriveSemanticMethod = ( methods : string [ ] ) : Method => {
194
185
if ( methods . includes ( 'get' ) ) return 'GET'
195
186
if ( methods . includes ( 'post' ) ) return 'POST'
0 commit comments