@@ -41,39 +41,83 @@ export default class GeneratorConfig {
4141
4242 const operationId = op . operationId . toLowerCase ( ) ;
4343 const isReadOperation = operationId . startsWith ( 'get' ) || operationId . startsWith ( 'list' ) || operationId . startsWith ( 'count' ) || operationId . includes ( 'read' ) || operationId . includes ( 'fetch' ) ;
44- const isWriteOperation = operationId . startsWith ( 'create' ) || operationId . startsWith ( 'add' ) || operationId . startsWith ( 'update' ) || operationId . startsWith ( 'put' ) || operationId . includes ( 'save' ) ;
44+ const isCreateOperation = operationId . startsWith ( 'create' ) || operationId . startsWith ( 'add' ) || ( method . toLowerCase ( ) === 'post' ) ;
45+ const isUpdateOperation = operationId . startsWith ( 'update' ) || operationId . startsWith ( 'put' ) || ( method . toLowerCase ( ) === 'put' ) ;
4546 const isDeleteOperation = operationId . startsWith ( 'delete' ) || operationId . includes ( 'remove' ) ;
4647
4748 if ( isReadOperation ) {
4849 // Generate data source for read operations
49- const dsName = operationId . replace ( / ^ ( g e t | l i s t | c o u n t | r e a d | f e t c h ) / i, '' ) . toLowerCase ( ) || pathKey . replace ( / [ \/ { \} ] / g, '' ) . replace ( / \/ / g, '_' ) ;
50- const cleanDsName = dsName . replace ( / ^ _ + | _ + $ / g, '' ) ;
51- if ( cleanDsName ) {
52- if ( ! config . data_sources [ cleanDsName ] ) config . data_sources [ cleanDsName ] = { } ;
53- config . data_sources [ cleanDsName ] [ 'read' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
50+ const dsName = this . extractResourceNameFromPath ( pathKey ) . toLowerCase ( ) ;
51+ if ( dsName ) {
52+ if ( ! config . data_sources [ dsName ] ) config . data_sources [ dsName ] = { } ;
53+ config . data_sources [ dsName ] [ 'read' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
5454 }
55- } else if ( isWriteOperation || ( ! isReadOperation && ! isDeleteOperation ) ) {
56- // Generate resource for write operations (create, update) or other operations
57- const resourceName = operationId . replace ( / ^ ( c r e a t e | p u t | a d d | u p d a t e ) / i, '' ) . toLowerCase ( ) || pathKey . replace ( / [ \/ { \} ] / g, '' ) . replace ( / \/ / g, '_' ) ;
58- const cleanResourceName = resourceName . replace ( / ^ _ + | _ + $ / g, '' ) ;
59- if ( cleanResourceName ) {
60- if ( ! config . resources [ cleanResourceName ] ) config . resources [ cleanResourceName ] = { } ;
61- const operationType = isWriteOperation && operationId . includes ( 'update' ) ? 'put' : method . toLowerCase ( ) ;
62- config . resources [ cleanResourceName ] [ operationType ] = { path : pathKey , method : method . toUpperCase ( ) } ;
55+
56+ // Also add as resource read operation
57+ const resourceName = this . extractResourceNameFromPath ( pathKey ) . toLowerCase ( ) ;
58+ if ( resourceName ) {
59+ if ( ! config . resources [ resourceName ] ) config . resources [ resourceName ] = { } ;
60+ config . resources [ resourceName ] [ 'read' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
61+ }
62+ } else if ( isCreateOperation ) {
63+ // Generate resource for create operations
64+ const resourceName = this . extractResourceNameFromPath ( pathKey ) . toLowerCase ( ) ;
65+ if ( resourceName ) {
66+ if ( ! config . resources [ resourceName ] ) config . resources [ resourceName ] = { } ;
67+ config . resources [ resourceName ] [ 'create' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
68+ }
69+ } else if ( isUpdateOperation ) {
70+ // Generate resource for update operations
71+ const resourceName = this . extractResourceNameFromPath ( pathKey ) . toLowerCase ( ) ;
72+ if ( resourceName ) {
73+ if ( ! config . resources [ resourceName ] ) config . resources [ resourceName ] = { } ;
74+ config . resources [ resourceName ] [ 'update' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
6375 }
6476 } else if ( isDeleteOperation ) {
65- // Handle delete operations - try to attach to existing resources or create new ones
66- const resourceName = operationId . replace ( / ^ ( d e l e t e | r e m o v e ) / i, '' ) . toLowerCase ( ) || pathKey . replace ( / [ \/ { \} ] / g, '' ) . replace ( / \/ / g, '_' ) ;
67- const cleanResourceName = resourceName . replace ( / ^ _ + | _ + $ / g, '' ) ;
68- if ( cleanResourceName ) {
69- if ( ! config . resources [ cleanResourceName ] ) config . resources [ cleanResourceName ] = { } ;
70- config . resources [ cleanResourceName ] [ 'delete' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
77+ // Handle delete operations
78+ const resourceName = this . extractResourceNameFromPath ( pathKey ) . toLowerCase ( ) ;
79+ if ( resourceName ) {
80+ if ( ! config . resources [ resourceName ] ) config . resources [ resourceName ] = { } ;
81+ config . resources [ resourceName ] [ 'delete' ] = { path : pathKey , method : method . toUpperCase ( ) } ;
7182 }
7283 }
7384 }
7485 }
7586 }
7687
88+ // Ensure every resource has both 'create' and 'read' operations
89+ // Remove resources that don't have the required operations
90+ const resourcesToRemove : string [ ] = [ ] ;
91+
92+ for ( const [ resourceName , resourceConfig ] of Object . entries ( config . resources ) ) {
93+ const resource = resourceConfig as any ;
94+
95+ // If resource doesn't have 'create', try to use 'post' operation
96+ if ( ! resource . create && resource . post ) {
97+ resource . create = resource . post ;
98+ delete resource . post ;
99+ }
100+
101+ // If resource doesn't have 'read', try to find it in data sources
102+ if ( ! resource . read ) {
103+ const matchingDataSource = config . data_sources [ resourceName ] ;
104+ if ( matchingDataSource && matchingDataSource . read ) {
105+ resource . read = matchingDataSource . read ;
106+ }
107+ }
108+
109+ // If resource still doesn't have both 'create' and 'read', remove it
110+ if ( ! resource . create || ! resource . read ) {
111+ console . log ( `Removing resource '${ resourceName } ' - missing required operations (create: ${ ! ! resource . create } , read: ${ ! ! resource . read } )` ) ;
112+ resourcesToRemove . push ( resourceName ) ;
113+ }
114+ }
115+
116+ // Remove invalid resources
117+ for ( const resourceName of resourcesToRemove ) {
118+ delete config . resources [ resourceName ] ;
119+ }
120+
77121 // Remove empty objects
78122 if ( Object . keys ( config . resources ) . length === 0 ) delete config . resources ;
79123 if ( Object . keys ( config . data_sources ) . length === 0 ) delete config . data_sources ;
@@ -90,6 +134,30 @@ export default class GeneratorConfig {
90134 const outputFile = path . join ( data . outputPath , data . outputFileName ) ;
91135 fs . writeFileSync ( outputFile , yamlStr , 'utf-8' ) ;
92136 }
137+
138+ /**
139+ * Extract resource name from API path.
140+ * Converts paths like "/alert-custom-field" to "alertcustomfield"
141+ * and "/alert-custom-field/{id}" to "alertcustomfield"
142+ */
143+ private static extractResourceNameFromPath ( path : string ) : string {
144+ // Remove leading slash and anything after the first parameter
145+ const pathParts = path . replace ( / ^ \/ / , '' ) . split ( '/' ) ;
146+ let resourcePath = pathParts [ 0 ] || '' ;
147+
148+ // Handle paths that end with specific patterns like /count, /get-list, etc.
149+ if ( resourcePath . includes ( '-count' ) || resourcePath . includes ( '-get-list' ) ) {
150+ resourcePath = resourcePath . replace ( / - c o u n t $ | - g e t - l i s t $ / , '' ) ;
151+ }
152+
153+ // Convert kebab-case to snake_case and remove special characters
154+ const resourceName = resourcePath
155+ . replace ( / - / g, '' ) // Remove hyphens
156+ . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '' ) // Remove any other special characters
157+ . toLowerCase ( ) ;
158+
159+ return resourceName ;
160+ }
93161}
94162
95163
0 commit comments