@api-client/core 0.18.7 → 0.18.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/src/modeling/importers/JsonSchemaImporter.d.ts +4 -0
- package/build/src/modeling/importers/JsonSchemaImporter.d.ts.map +1 -1
- package/build/src/modeling/importers/JsonSchemaImporter.js +89 -16
- package/build/src/modeling/importers/JsonSchemaImporter.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +23 -23
- package/package.json +1 -1
- package/src/modeling/importers/JsonSchemaImporter.ts +111 -20
- package/tests/fixtures/schemas/arrays.json +35 -0
- package/tests/fixtures/schemas/complex.json +41 -0
- package/tests/fixtures/schemas/enumerated_values.json +11 -0
- package/tests/fixtures/schemas/person.json +21 -0
- package/tests/fixtures/schemas/regexp.json +12 -0
- package/tests/unit/modeling/importers/json_schema_importer.spec.ts +137 -0
|
@@ -42062,22 +42062,22 @@
|
|
|
42062
42062
|
"@id": "#209"
|
|
42063
42063
|
},
|
|
42064
42064
|
{
|
|
42065
|
-
"@id": "#
|
|
42065
|
+
"@id": "#191"
|
|
42066
42066
|
},
|
|
42067
42067
|
{
|
|
42068
|
-
"@id": "#
|
|
42068
|
+
"@id": "#197"
|
|
42069
42069
|
},
|
|
42070
42070
|
{
|
|
42071
42071
|
"@id": "#194"
|
|
42072
42072
|
},
|
|
42073
42073
|
{
|
|
42074
|
-
"@id": "#
|
|
42074
|
+
"@id": "#203"
|
|
42075
42075
|
},
|
|
42076
42076
|
{
|
|
42077
|
-
"@id": "#
|
|
42077
|
+
"@id": "#200"
|
|
42078
42078
|
},
|
|
42079
42079
|
{
|
|
42080
|
-
"@id": "#
|
|
42080
|
+
"@id": "#206"
|
|
42081
42081
|
},
|
|
42082
42082
|
{
|
|
42083
42083
|
"@id": "#209"
|
|
@@ -42810,15 +42810,15 @@
|
|
|
42810
42810
|
"@id": "#219"
|
|
42811
42811
|
},
|
|
42812
42812
|
{
|
|
42813
|
-
"@id": "#216"
|
|
42814
|
-
},
|
|
42815
|
-
{
|
|
42816
42813
|
"@id": "#210"
|
|
42817
42814
|
},
|
|
42818
42815
|
{
|
|
42819
42816
|
"@id": "#213"
|
|
42820
42817
|
},
|
|
42821
42818
|
{
|
|
42819
|
+
"@id": "#216"
|
|
42820
|
+
},
|
|
42821
|
+
{
|
|
42822
42822
|
"@id": "#219"
|
|
42823
42823
|
}
|
|
42824
42824
|
],
|
|
@@ -43436,7 +43436,7 @@
|
|
|
43436
43436
|
"doc:ExternalDomainElement",
|
|
43437
43437
|
"doc:DomainElement"
|
|
43438
43438
|
],
|
|
43439
|
-
"doc:raw": "
|
|
43439
|
+
"doc:raw": "countryCode: \"BE\"\ngraydonEnterpriseId: 1057155523\nregistrationId: \"0422319093\"\nvatNumber: \"BE0422319093\"\ngraydonCompanyId: \"0422319093\"\nisBranchOffice: false\n",
|
|
43440
43440
|
"core:mediaType": "application/yaml",
|
|
43441
43441
|
"sourcemaps:sources": [
|
|
43442
43442
|
{
|
|
@@ -43478,7 +43478,7 @@
|
|
|
43478
43478
|
"doc:ExternalDomainElement",
|
|
43479
43479
|
"doc:DomainElement"
|
|
43480
43480
|
],
|
|
43481
|
-
"doc:raw": "
|
|
43481
|
+
"doc:raw": "addressType: 'REGISTERED-OFFICE-ADDRESS'\nstreetName: 'UITBREIDINGSTRAAT'\nhouseNumber: '84'\nhouseNumberAddition: '/1'\npostalCode: '2600'\ncity: 'BERCHEM (ANTWERPEN)'\ncountry: 'Belgium'\ncountryCode: 'BE'\nfullFormatedAddress: \"UITBREIDINGSTRAAT 84 /1, 2600 BERCHEM (ANTWERPEN), BELIUM\"\n",
|
|
43482
43482
|
"core:mediaType": "application/yaml",
|
|
43483
43483
|
"sourcemaps:sources": [
|
|
43484
43484
|
{
|
|
@@ -43499,7 +43499,7 @@
|
|
|
43499
43499
|
"doc:ExternalDomainElement",
|
|
43500
43500
|
"doc:DomainElement"
|
|
43501
43501
|
],
|
|
43502
|
-
"doc:raw": "code: '
|
|
43502
|
+
"doc:raw": "code: 'J'\ndescription: 'Information and communication'\n",
|
|
43503
43503
|
"core:mediaType": "application/yaml",
|
|
43504
43504
|
"sourcemaps:sources": [
|
|
43505
43505
|
{
|
|
@@ -43520,7 +43520,7 @@
|
|
|
43520
43520
|
"doc:ExternalDomainElement",
|
|
43521
43521
|
"doc:DomainElement"
|
|
43522
43522
|
],
|
|
43523
|
-
"doc:raw": "
|
|
43523
|
+
"doc:raw": "class: '3'\ndescription: '150 - 300'\nnumberOfFte: 5500\nnumberOfEmployees: 5232\n",
|
|
43524
43524
|
"core:mediaType": "application/yaml",
|
|
43525
43525
|
"sourcemaps:sources": [
|
|
43526
43526
|
{
|
|
@@ -43541,7 +43541,7 @@
|
|
|
43541
43541
|
"doc:ExternalDomainElement",
|
|
43542
43542
|
"doc:DomainElement"
|
|
43543
43543
|
],
|
|
43544
|
-
"doc:raw": "
|
|
43544
|
+
"doc:raw": "code: '7487'\ndescription: 'Financial and insurance activities'\ntype: \"PRIMARY\"\nclassificationCode: 'BE_NACEBEL2008'\nactivityGroupCode: 'ABCDE'\n",
|
|
43545
43545
|
"core:mediaType": "application/yaml",
|
|
43546
43546
|
"sourcemaps:sources": [
|
|
43547
43547
|
{
|
|
@@ -44232,7 +44232,7 @@
|
|
|
44232
44232
|
"doc:ExternalDomainElement",
|
|
44233
44233
|
"doc:DomainElement"
|
|
44234
44234
|
],
|
|
44235
|
-
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '
|
|
44235
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
|
|
44236
44236
|
"core:mediaType": "application/yaml",
|
|
44237
44237
|
"sourcemaps:sources": [
|
|
44238
44238
|
{
|
|
@@ -44253,7 +44253,7 @@
|
|
|
44253
44253
|
"doc:ExternalDomainElement",
|
|
44254
44254
|
"doc:DomainElement"
|
|
44255
44255
|
],
|
|
44256
|
-
"doc:raw": "
|
|
44256
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
|
|
44257
44257
|
"core:mediaType": "application/yaml",
|
|
44258
44258
|
"sourcemaps:sources": [
|
|
44259
44259
|
{
|
|
@@ -44274,7 +44274,7 @@
|
|
|
44274
44274
|
"doc:ExternalDomainElement",
|
|
44275
44275
|
"doc:DomainElement"
|
|
44276
44276
|
],
|
|
44277
|
-
"doc:raw": "type: 'GENERAL'\
|
|
44277
|
+
"doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
|
|
44278
44278
|
"core:mediaType": "application/yaml",
|
|
44279
44279
|
"sourcemaps:sources": [
|
|
44280
44280
|
{
|
|
@@ -44756,7 +44756,7 @@
|
|
|
44756
44756
|
{
|
|
44757
44757
|
"@id": "#193/source-map/lexical/element_0",
|
|
44758
44758
|
"sourcemaps:element": "amf://id#193",
|
|
44759
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44759
|
+
"sourcemaps:value": "[(1,0)-(7,0)]"
|
|
44760
44760
|
},
|
|
44761
44761
|
{
|
|
44762
44762
|
"@id": "#196/source-map/lexical/element_0",
|
|
@@ -44766,22 +44766,22 @@
|
|
|
44766
44766
|
{
|
|
44767
44767
|
"@id": "#199/source-map/lexical/element_0",
|
|
44768
44768
|
"sourcemaps:element": "amf://id#199",
|
|
44769
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44769
|
+
"sourcemaps:value": "[(1,0)-(10,0)]"
|
|
44770
44770
|
},
|
|
44771
44771
|
{
|
|
44772
44772
|
"@id": "#202/source-map/lexical/element_0",
|
|
44773
44773
|
"sourcemaps:element": "amf://id#202",
|
|
44774
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44774
|
+
"sourcemaps:value": "[(1,0)-(3,0)]"
|
|
44775
44775
|
},
|
|
44776
44776
|
{
|
|
44777
44777
|
"@id": "#205/source-map/lexical/element_0",
|
|
44778
44778
|
"sourcemaps:element": "amf://id#205",
|
|
44779
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44779
|
+
"sourcemaps:value": "[(1,0)-(5,0)]"
|
|
44780
44780
|
},
|
|
44781
44781
|
{
|
|
44782
44782
|
"@id": "#208/source-map/lexical/element_0",
|
|
44783
44783
|
"sourcemaps:element": "amf://id#208",
|
|
44784
|
-
"sourcemaps:value": "[(1,0)-(
|
|
44784
|
+
"sourcemaps:value": "[(1,0)-(6,0)]"
|
|
44785
44785
|
},
|
|
44786
44786
|
{
|
|
44787
44787
|
"@id": "#223/source-map/lexical/element_0",
|
|
@@ -45121,12 +45121,12 @@
|
|
|
45121
45121
|
{
|
|
45122
45122
|
"@id": "#215/source-map/lexical/element_0",
|
|
45123
45123
|
"sourcemaps:element": "amf://id#215",
|
|
45124
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45124
|
+
"sourcemaps:value": "[(1,0)-(6,0)]"
|
|
45125
45125
|
},
|
|
45126
45126
|
{
|
|
45127
45127
|
"@id": "#218/source-map/lexical/element_0",
|
|
45128
45128
|
"sourcemaps:element": "amf://id#218",
|
|
45129
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45129
|
+
"sourcemaps:value": "[(1,0)-(7,0)]"
|
|
45130
45130
|
},
|
|
45131
45131
|
{
|
|
45132
45132
|
"@id": "#221/source-map/lexical/element_0",
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import type { PropertySchema } from '../types.js'
|
|
|
7
7
|
import type { PropertyWebBindings } from '../Bindings.js'
|
|
8
8
|
import type { DomainPropertyFormat, DomainPropertyType } from '../DataFormat.js'
|
|
9
9
|
import { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'
|
|
10
|
+
import { nanoid } from '../../nanoid.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Represents a single message (info, warning, or error) generated during the import process.
|
|
@@ -86,34 +87,52 @@ export class JsonSchemaImporter {
|
|
|
86
87
|
// Build a flat map of all definitions and $id-indexed schemas
|
|
87
88
|
const definitionMap = new Map<string, JSONSchema7>()
|
|
88
89
|
const idMap = new Map<string, JSONSchema7>()
|
|
90
|
+
const processedSchemas = new Set<JSONSchema7>() // Track processed schema objects to avoid duplicates
|
|
91
|
+
|
|
89
92
|
for (const schema of schemas) {
|
|
90
93
|
// Add $id mapping if present
|
|
91
94
|
if (schema.contents.$id) {
|
|
92
95
|
idMap.set(schema.contents.$id, schema.contents)
|
|
96
|
+
// Add the entire schema to the definitions maps as well as they can be referenced by other schemas.
|
|
97
|
+
definitionMap.set(schema.contents.$id, schema.contents)
|
|
93
98
|
}
|
|
94
99
|
// Add the schema itself by its path
|
|
95
100
|
definitionMap.set(schema.path, schema.contents)
|
|
96
101
|
// Add all definitions inside this schema
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
for (const [defName, defSchema] of Object.entries(defs)) {
|
|
102
|
+
const definitions = schema.contents.definitions
|
|
103
|
+
const defs = (schema.contents as unknown as { $defs: Record<string, JSONSchema7Definition> }).$defs
|
|
104
|
+
|
|
105
|
+
if (definitions) {
|
|
106
|
+
for (const [defName, defSchema] of Object.entries(definitions)) {
|
|
103
107
|
if (typeof defSchema === 'object') {
|
|
104
|
-
// Use a JSON pointer for the key
|
|
108
|
+
// Use a JSON pointer for the key - include both full path and short form
|
|
105
109
|
definitionMap.set(`${schema.path}#/definitions/${defName}`, defSchema as JSONSchema7)
|
|
106
|
-
// Also allow lookup by just #/definitions/defName for single-file schemas
|
|
107
110
|
definitionMap.set(`#/definitions/${defName}`, defSchema as JSONSchema7)
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
113
|
}
|
|
114
|
+
|
|
115
|
+
if (defs) {
|
|
116
|
+
for (const [defName, defSchema] of Object.entries(defs)) {
|
|
117
|
+
if (typeof defSchema === 'object') {
|
|
118
|
+
// Use a JSON pointer for the key - include both full path and short form
|
|
119
|
+
definitionMap.set(`${schema.path}#/$defs/${defName}`, defSchema as JSONSchema7)
|
|
120
|
+
definitionMap.set(`#/$defs/${defName}`, defSchema as JSONSchema7)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
// == Pass 1: Create all entities ==
|
|
114
127
|
for (const [key, schema] of definitionMap.entries()) {
|
|
128
|
+
// Skip if this schema object has already been processed
|
|
129
|
+
if (processedSchemas.has(schema)) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
|
|
115
133
|
if (typeof schema === 'object' && schema.type === 'object') {
|
|
116
134
|
this.createEntity(key, schema, key)
|
|
135
|
+
processedSchemas.add(schema)
|
|
117
136
|
} else if (this.isEnum(schema)) {
|
|
118
137
|
this.enums.set(key, schema)
|
|
119
138
|
} else {
|
|
@@ -122,15 +141,20 @@ export class JsonSchemaImporter {
|
|
|
122
141
|
}
|
|
123
142
|
// Also create entities for all $id-indexed schemas if not already present
|
|
124
143
|
for (const [id, schema] of idMap.entries()) {
|
|
144
|
+
// Skip if this schema object has already been processed
|
|
145
|
+
if (processedSchemas.has(schema)) {
|
|
146
|
+
continue
|
|
147
|
+
}
|
|
148
|
+
|
|
125
149
|
if (!this.refMap.has(id) && typeof schema === 'object' && schema.type === 'object') {
|
|
126
150
|
this.createEntity(id, schema, id)
|
|
127
|
-
|
|
151
|
+
processedSchemas.add(schema)
|
|
152
|
+
} else if (this.isEnum(schema) && !this.enums.has(id)) {
|
|
128
153
|
this.enums.set(id, schema)
|
|
129
154
|
} else {
|
|
130
155
|
this.report('warning', `Skipping non-object schema at ${id}`, id)
|
|
131
156
|
}
|
|
132
157
|
}
|
|
133
|
-
|
|
134
158
|
// == Pass 2: Populate entities ==
|
|
135
159
|
for (const [refPath, entityKey] of this.refMap.entries()) {
|
|
136
160
|
const entity = this.domain.findEntity(entityKey)
|
|
@@ -173,10 +197,10 @@ export class JsonSchemaImporter {
|
|
|
173
197
|
// Try direct match
|
|
174
198
|
if (definitionMap.has(refPath)) return definitionMap.get(refPath)
|
|
175
199
|
if (idMap.has(refPath)) return idMap.get(refPath)
|
|
176
|
-
// Try to resolve #/definitions/Name from any schema
|
|
177
|
-
if (refPath.startsWith('#/definitions/')) {
|
|
200
|
+
// Try to resolve #/definitions/Name or #/$defs/Name from any schema
|
|
201
|
+
if (refPath.startsWith('#/definitions/') || refPath.startsWith('#/$defs/')) {
|
|
178
202
|
for (const [key, schema] of definitionMap.entries()) {
|
|
179
|
-
if (key
|
|
203
|
+
if (key === refPath) return schema
|
|
180
204
|
}
|
|
181
205
|
}
|
|
182
206
|
// Try to resolve by $id fragment
|
|
@@ -192,7 +216,17 @@ export class JsonSchemaImporter {
|
|
|
192
216
|
* Helper for entity creation, can be extended for custom logic.
|
|
193
217
|
*/
|
|
194
218
|
private createEntity(name: string, schema: JSONSchema7, refPath: string): DomainEntity {
|
|
195
|
-
|
|
219
|
+
let fixedName = schema.title || name
|
|
220
|
+
|
|
221
|
+
// Extract just the definition name from JSON pointers (both short and full paths)
|
|
222
|
+
if (name.includes('#/definitions/')) {
|
|
223
|
+
const parts = name.split('#/definitions/')
|
|
224
|
+
fixedName = schema.title || parts[parts.length - 1]
|
|
225
|
+
} else if (name.includes('#/$defs/')) {
|
|
226
|
+
const parts = name.split('#/$defs/')
|
|
227
|
+
fixedName = schema.title || parts[parts.length - 1]
|
|
228
|
+
}
|
|
229
|
+
|
|
196
230
|
const cleanName = toDatabaseTableName(fixedName, 'untitled_entity')
|
|
197
231
|
const entity = this.model.addEntity({
|
|
198
232
|
info: {
|
|
@@ -210,6 +244,24 @@ export class JsonSchemaImporter {
|
|
|
210
244
|
return entity
|
|
211
245
|
}
|
|
212
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Generates a meaningful name for inline entities based on their parent context.
|
|
249
|
+
*/
|
|
250
|
+
private generateInlineEntityName(parentEntityKey: string, propName: string, schema: JSONSchema7): string {
|
|
251
|
+
// Try to use the schema title first
|
|
252
|
+
if (schema.title) {
|
|
253
|
+
return toDatabaseTableName(schema.title, 'untitled_entity')
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Find the parent entity to create a meaningful name
|
|
257
|
+
const parentEntity = this.domain.findEntity(parentEntityKey)
|
|
258
|
+
const parentName = parentEntity?.info.name || 'unknown'
|
|
259
|
+
|
|
260
|
+
// Create a name like "User_Address" or "Order_ShippingInfo"
|
|
261
|
+
const combinedName = `${parentName}_${propName}`
|
|
262
|
+
return toDatabaseTableName(combinedName, 'untitled_entity')
|
|
263
|
+
}
|
|
264
|
+
|
|
213
265
|
/**
|
|
214
266
|
* Populates a DomainEntity with its properties, associations, and parent relationships.
|
|
215
267
|
*/
|
|
@@ -285,7 +337,11 @@ export class JsonSchemaImporter {
|
|
|
285
337
|
* Recursively analyzes a schema definition to find all contained primitive types and `$ref`s.
|
|
286
338
|
* It's used to understand the nature of a property (is it a primitive, an association, or a mix).
|
|
287
339
|
*/
|
|
288
|
-
private collectTypesAndRefs(
|
|
340
|
+
private collectTypesAndRefs(
|
|
341
|
+
schema: JSONSchema7Definition,
|
|
342
|
+
parentEntityKey?: string,
|
|
343
|
+
propName?: string
|
|
344
|
+
): {
|
|
289
345
|
refs: Set<string>
|
|
290
346
|
types: Set<JSONSchema7TypeName>
|
|
291
347
|
isArray: boolean
|
|
@@ -308,11 +364,30 @@ export class JsonSchemaImporter {
|
|
|
308
364
|
}
|
|
309
365
|
}
|
|
310
366
|
|
|
367
|
+
// Handle inline object types by creating entities immediately
|
|
368
|
+
if (schema.type === 'object' && schema.properties && parentEntityKey && propName) {
|
|
369
|
+
// Create an entity for this inline object immediately
|
|
370
|
+
const inlineEntityName = this.generateInlineEntityName(parentEntityKey, propName, schema)
|
|
371
|
+
const inlineEntity = this.createEntity(inlineEntityName, schema, inlineEntityName)
|
|
372
|
+
|
|
373
|
+
// Populate it immediately since we have the schema
|
|
374
|
+
this.populateEntity(inlineEntity, schema)
|
|
375
|
+
|
|
376
|
+
// Add a reference to it so it gets treated as an association
|
|
377
|
+
collected.refs.add(inlineEntityName)
|
|
378
|
+
|
|
379
|
+
return collected
|
|
380
|
+
}
|
|
381
|
+
|
|
311
382
|
if (schema.type === 'array') {
|
|
312
383
|
collected.isArray = true
|
|
313
384
|
if (typeof schema.items === 'object') {
|
|
314
|
-
// Recurse into items
|
|
315
|
-
const itemInfo = this.collectTypesAndRefs(
|
|
385
|
+
// Recurse into items - pass along parent context for inline objects in arrays
|
|
386
|
+
const itemInfo = this.collectTypesAndRefs(
|
|
387
|
+
Array.isArray(schema.items) ? schema.items[0] : schema.items,
|
|
388
|
+
parentEntityKey,
|
|
389
|
+
propName ? `${propName}_item` : undefined
|
|
390
|
+
)
|
|
316
391
|
itemInfo.refs.forEach((r) => collected.refs.add(r))
|
|
317
392
|
itemInfo.types.forEach((t) => collected.types.add(t))
|
|
318
393
|
}
|
|
@@ -322,7 +397,7 @@ export class JsonSchemaImporter {
|
|
|
322
397
|
const choices = schema.anyOf || schema.oneOf
|
|
323
398
|
if (choices) {
|
|
324
399
|
for (const choice of choices) {
|
|
325
|
-
const choiceInfo = this.collectTypesAndRefs(choice)
|
|
400
|
+
const choiceInfo = this.collectTypesAndRefs(choice, parentEntityKey)
|
|
326
401
|
choiceInfo.refs.forEach((r) => collected.refs.add(r))
|
|
327
402
|
choiceInfo.types.forEach((t) => collected.types.add(t))
|
|
328
403
|
if (choiceInfo.isArray) {
|
|
@@ -331,6 +406,20 @@ export class JsonSchemaImporter {
|
|
|
331
406
|
}
|
|
332
407
|
}
|
|
333
408
|
|
|
409
|
+
if (schema.enum) {
|
|
410
|
+
// If the schema has an enum, we treat it as a string type with specific values.
|
|
411
|
+
collected.types.add('string')
|
|
412
|
+
// consider the following schema: `"enum": ["one", "two", "three"]`
|
|
413
|
+
const id = nanoid(8)
|
|
414
|
+
this.enums.set(id, {
|
|
415
|
+
type: 'string',
|
|
416
|
+
oneOf: schema.enum.map((value) => ({
|
|
417
|
+
const: String(value), // Ensure enum values are strings
|
|
418
|
+
})),
|
|
419
|
+
})
|
|
420
|
+
collected.refs.add(id) // Add the enum reference
|
|
421
|
+
}
|
|
422
|
+
|
|
334
423
|
return collected
|
|
335
424
|
}
|
|
336
425
|
|
|
@@ -344,8 +433,9 @@ export class JsonSchemaImporter {
|
|
|
344
433
|
isRequired: boolean
|
|
345
434
|
): void {
|
|
346
435
|
// Analyze the property schema to understand its composition (primitives, refs, arrays).
|
|
347
|
-
|
|
348
|
-
|
|
436
|
+
// Pass entity context to collectTypesAndRefs for inline object handling
|
|
437
|
+
const analysis = this.collectTypesAndRefs(propSchema, entity.key, propName)
|
|
438
|
+
// console.log(`Analyzing property '${propName}' in entity '${entity.info.name}':`, analysis, propSchema)
|
|
349
439
|
// Case 1: If the property has `$ref` to an enum, we treat it as a DomainProperty.
|
|
350
440
|
if (analysis.refs.size === 1 && this.enums.has([...analysis.refs][0])) {
|
|
351
441
|
const prop = this.createEnumProperty(
|
|
@@ -635,6 +725,7 @@ export class JsonSchemaImporter {
|
|
|
635
725
|
}
|
|
636
726
|
|
|
637
727
|
if (Object.keys(schema).length > 0) {
|
|
728
|
+
// console.log(`Creating enum property '${propName}' with schema:`, schema)
|
|
638
729
|
prop.schema = schema
|
|
639
730
|
}
|
|
640
731
|
return prop
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://example.com/arrays.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"description": "Arrays of strings and objects",
|
|
5
|
+
"title": "Arrays",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"fruits": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "string"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"vegetables": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": { "$ref": "#/$defs/veggie" }
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"$defs": {
|
|
20
|
+
"veggie": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": [ "veggieName", "veggieLike" ],
|
|
23
|
+
"properties": {
|
|
24
|
+
"veggieName": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "The name of the vegetable."
|
|
27
|
+
},
|
|
28
|
+
"veggieLike": {
|
|
29
|
+
"type": "boolean",
|
|
30
|
+
"description": "Do I like this vegetable?"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://example.com/complex-object.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "Complex Object",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"name": {
|
|
8
|
+
"type": "string"
|
|
9
|
+
},
|
|
10
|
+
"age": {
|
|
11
|
+
"type": "integer",
|
|
12
|
+
"minimum": 0
|
|
13
|
+
},
|
|
14
|
+
"address": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"street": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"city": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"state": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"postalCode": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"pattern": "\\d{5}"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": ["street", "city", "state", "postalCode"]
|
|
32
|
+
},
|
|
33
|
+
"hobbies": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"required": ["name", "age"]
|
|
41
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://example.com/enumerated-values.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "Enumerated Values",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"data": {
|
|
8
|
+
"enum": [42, true, "hello", null, [1, 2, 3]]
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://example.com/person.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "Person",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"firstName": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "The person's first name."
|
|
10
|
+
},
|
|
11
|
+
"lastName": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "The person's last name."
|
|
14
|
+
},
|
|
15
|
+
"age": {
|
|
16
|
+
"description": "Age in years which must be equal to or greater than zero.",
|
|
17
|
+
"type": "integer",
|
|
18
|
+
"minimum": 0
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://example.com/regex-pattern.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "Regular Expression Pattern",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"code": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"pattern": "^[A-Z]{3}-\\d{3}$"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|