@api-client/core 0.19.19 → 0.19.21

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.
Files changed (130) hide show
  1. package/build/src/authorization/Utils.js +3 -3
  2. package/build/src/authorization/Utils.js.map +1 -1
  3. package/build/src/modeling/ApiModel.d.ts +16 -5
  4. package/build/src/modeling/ApiModel.d.ts.map +1 -1
  5. package/build/src/modeling/ApiModel.js +17 -2
  6. package/build/src/modeling/ApiModel.js.map +1 -1
  7. package/build/src/modeling/ApiValidation.d.ts.map +1 -1
  8. package/build/src/modeling/ApiValidation.js +2 -1
  9. package/build/src/modeling/ApiValidation.js.map +1 -1
  10. package/build/src/modeling/DomainProperty.d.ts +12 -0
  11. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  12. package/build/src/modeling/DomainProperty.js +23 -28
  13. package/build/src/modeling/DomainProperty.js.map +1 -1
  14. package/build/src/modeling/DomainSerialization.js +1 -1
  15. package/build/src/modeling/DomainSerialization.js.map +1 -1
  16. package/build/src/modeling/ExposedEntity.d.ts +15 -1
  17. package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
  18. package/build/src/modeling/ExposedEntity.js +42 -4
  19. package/build/src/modeling/ExposedEntity.js.map +1 -1
  20. package/build/src/modeling/actions/Action.d.ts.map +1 -1
  21. package/build/src/modeling/actions/Action.js +1 -0
  22. package/build/src/modeling/actions/Action.js.map +1 -1
  23. package/build/src/modeling/actions/ListAction.d.ts +3 -17
  24. package/build/src/modeling/actions/ListAction.d.ts.map +1 -1
  25. package/build/src/modeling/actions/ListAction.js +18 -38
  26. package/build/src/modeling/actions/ListAction.js.map +1 -1
  27. package/build/src/modeling/actions/SearchAction.d.ts +4 -4
  28. package/build/src/modeling/actions/SearchAction.d.ts.map +1 -1
  29. package/build/src/modeling/actions/SearchAction.js +16 -13
  30. package/build/src/modeling/actions/SearchAction.js.map +1 -1
  31. package/build/src/modeling/generators/oas_312/OasGenerator.d.ts +32 -0
  32. package/build/src/modeling/generators/oas_312/OasGenerator.d.ts.map +1 -0
  33. package/build/src/modeling/generators/oas_312/OasGenerator.js +1452 -0
  34. package/build/src/modeling/generators/oas_312/OasGenerator.js.map +1 -0
  35. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.d.ts +27 -0
  36. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.d.ts.map +1 -0
  37. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.js +295 -0
  38. package/build/src/modeling/generators/oas_312/OasSchemaGenerator.js.map +1 -0
  39. package/build/src/modeling/generators/oas_312/types.d.ts +1010 -0
  40. package/build/src/modeling/generators/oas_312/types.d.ts.map +1 -0
  41. package/build/src/modeling/generators/oas_312/types.js +2 -0
  42. package/build/src/modeling/generators/oas_312/types.js.map +1 -0
  43. package/build/src/modeling/generators/oas_320/OasGenerator.d.ts +16 -0
  44. package/build/src/modeling/generators/oas_320/OasGenerator.d.ts.map +1 -0
  45. package/build/src/modeling/generators/oas_320/OasGenerator.js +306 -0
  46. package/build/src/modeling/generators/oas_320/OasGenerator.js.map +1 -0
  47. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.d.ts +25 -0
  48. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.d.ts.map +1 -0
  49. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.js +237 -0
  50. package/build/src/modeling/generators/oas_320/OasSchemaGenerator.js.map +1 -0
  51. package/build/src/modeling/generators/oas_320/types.d.ts +1219 -0
  52. package/build/src/modeling/generators/oas_320/types.d.ts.map +1 -0
  53. package/build/src/modeling/generators/oas_320/types.js +2 -0
  54. package/build/src/modeling/generators/oas_320/types.js.map +1 -0
  55. package/build/src/modeling/helpers/Intelisense.d.ts +1 -1
  56. package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -1
  57. package/build/src/modeling/helpers/Intelisense.js +4 -2
  58. package/build/src/modeling/helpers/Intelisense.js.map +1 -1
  59. package/build/src/modeling/types.d.ts +50 -13
  60. package/build/src/modeling/types.d.ts.map +1 -1
  61. package/build/src/modeling/types.js.map +1 -1
  62. package/build/src/modeling/validation/api_model_rules.d.ts +1 -0
  63. package/build/src/modeling/validation/api_model_rules.d.ts.map +1 -1
  64. package/build/src/modeling/validation/api_model_rules.js +105 -29
  65. package/build/src/modeling/validation/api_model_rules.js.map +1 -1
  66. package/build/src/models/ProjectRequest.d.ts.map +1 -1
  67. package/build/src/models/ProjectRequest.js +0 -4
  68. package/build/src/models/ProjectRequest.js.map +1 -1
  69. package/build/src/models/transformers/ArcDexieTransformer.d.ts.map +1 -1
  70. package/build/src/models/transformers/ArcDexieTransformer.js +0 -4
  71. package/build/src/models/transformers/ArcDexieTransformer.js.map +1 -1
  72. package/build/src/models/transformers/ImportUtils.js +1 -1
  73. package/build/src/models/transformers/ImportUtils.js.map +1 -1
  74. package/build/src/models/transformers/PostmanBackupTransformer.d.ts.map +1 -1
  75. package/build/src/models/transformers/PostmanBackupTransformer.js +0 -4
  76. package/build/src/models/transformers/PostmanBackupTransformer.js.map +1 -1
  77. package/build/src/runtime/constants.d.ts +7 -0
  78. package/build/src/runtime/constants.d.ts.map +1 -0
  79. package/build/src/runtime/constants.js +8 -0
  80. package/build/src/runtime/constants.js.map +1 -0
  81. package/build/src/runtime/http-engine/ntlm/Des.d.ts.map +1 -1
  82. package/build/src/runtime/http-engine/ntlm/Des.js +1 -0
  83. package/build/src/runtime/http-engine/ntlm/Des.js.map +1 -1
  84. package/build/src/runtime/variables/EvalFunctions.d.ts.map +1 -1
  85. package/build/src/runtime/variables/EvalFunctions.js +0 -1
  86. package/build/src/runtime/variables/EvalFunctions.js.map +1 -1
  87. package/build/tsconfig.tsbuildinfo +1 -1
  88. package/eslint.config.js +6 -0
  89. package/package.json +3 -1
  90. package/src/authorization/Utils.ts +3 -3
  91. package/src/modeling/ApiModel.ts +23 -8
  92. package/src/modeling/ApiValidation.ts +2 -0
  93. package/src/modeling/DomainProperty.ts +22 -18
  94. package/src/modeling/DomainSerialization.ts +1 -1
  95. package/src/modeling/ExposedEntity.ts +44 -4
  96. package/src/modeling/actions/Action.ts +1 -0
  97. package/src/modeling/actions/ListAction.ts +12 -30
  98. package/src/modeling/actions/SearchAction.ts +11 -8
  99. package/src/modeling/generators/oas_312/OasGenerator.ts +1685 -0
  100. package/src/modeling/generators/oas_312/OasSchemaGenerator.ts +322 -0
  101. package/src/modeling/generators/oas_312/types.ts +1052 -0
  102. package/src/modeling/generators/oas_320/OasGenerator.ts +359 -0
  103. package/src/modeling/generators/oas_320/OasSchemaGenerator.ts +255 -0
  104. package/src/modeling/generators/oas_320/types.ts +1259 -0
  105. package/src/modeling/helpers/Intelisense.ts +4 -2
  106. package/src/modeling/types.ts +55 -22
  107. package/src/modeling/validation/api_model_rules.ts +103 -32
  108. package/src/models/ProjectRequest.ts +0 -4
  109. package/src/models/transformers/ArcDexieTransformer.ts +0 -4
  110. package/src/models/transformers/ImportUtils.ts +1 -1
  111. package/src/models/transformers/PostmanBackupTransformer.ts +0 -5
  112. package/src/runtime/constants.ts +9 -0
  113. package/src/runtime/http-engine/ntlm/Des.ts +1 -0
  114. package/src/runtime/variables/EvalFunctions.ts +0 -1
  115. package/tests/test-utils.ts +6 -2
  116. package/tests/unit/decorators/observed.spec.ts +8 -24
  117. package/tests/unit/decorators/observed_recursive.spec.ts +0 -1
  118. package/tests/unit/events/EventsTestHelpers.ts +0 -1
  119. package/tests/unit/events/events_polyfills.ts +0 -1
  120. package/tests/unit/legacy-transformers/DataTestHelper.ts +0 -2
  121. package/tests/unit/legacy-transformers/LegacyExportProcessor.spec.ts +0 -1
  122. package/tests/unit/modeling/actions/ListAction.spec.ts +9 -69
  123. package/tests/unit/modeling/actions/SearchAction.spec.ts +9 -35
  124. package/tests/unit/modeling/api_model.spec.ts +28 -0
  125. package/tests/unit/modeling/definitions/sku.spec.ts +0 -2
  126. package/tests/unit/modeling/domain_property.spec.ts +20 -1
  127. package/tests/unit/modeling/exposed_entity.spec.ts +71 -0
  128. package/tests/unit/modeling/generators/OasGenerator.spec.ts +302 -0
  129. package/tests/unit/modeling/helpers/intellisense.spec.ts +1 -1
  130. package/tests/unit/modeling/validation/api_model_rules.spec.ts +113 -15
@@ -0,0 +1,322 @@
1
+ import type { ReferenceObject, SchemaObject } from './types.js'
2
+ import { AssociationWebBindings, PropertyWebBindings } from '../../Bindings.js'
3
+ import type { DomainEntity } from '../../DomainEntity.js'
4
+ import type { DomainProperty } from '../../DomainProperty.js'
5
+ import { SemanticType } from '../../Semantics.js'
6
+
7
+ interface SemanticExtension {
8
+ 'x-api-now-semantics'?: Record<string, unknown>
9
+ }
10
+
11
+ function getSemanticName(id: string): string {
12
+ return id.split('#')[1]
13
+ }
14
+
15
+ export class OasSchemaGenerator {
16
+ private memorySchemas: Record<string, SchemaObject> = {}
17
+ private memoryNames: Record<string, string> = {}
18
+
19
+ #hasFileUpload = false
20
+
21
+ /**
22
+ * A flag that determines whether any of the properties has the `FileURL` or `ImageURL` semantic.
23
+ */
24
+ get hasFileUpload(): boolean {
25
+ return this.#hasFileUpload
26
+ }
27
+
28
+ /**
29
+ * Retrieves the dictionary of all processed OAS JSON schemas.
30
+ */
31
+ public getSchemas(): Record<string, SchemaObject> {
32
+ const result: Record<string, SchemaObject> = {}
33
+ for (const [key, value] of Object.entries(this.memorySchemas)) {
34
+ result[this.memoryNames[key]] = value
35
+ }
36
+ return result
37
+ }
38
+
39
+ /**
40
+ * Generates schemas recursively for an entity and returns the $ref pointing to the root representation.
41
+ * @param entity
42
+ */
43
+ public generateRootRef(entity: DomainEntity): ReferenceObject {
44
+ this.generateEntity(entity)
45
+ return { $ref: `#/components/schemas/${this.generateSchemaKey(entity)}` }
46
+ }
47
+
48
+ /**
49
+ * Generates a schema key for an entity.
50
+ */
51
+ public generateSchemaKey(entity: DomainEntity): string {
52
+ return entity.info.name || 'entity ' + entity.key
53
+ }
54
+
55
+ private generateEntity(entity: DomainEntity): void {
56
+ if (this.memorySchemas[entity.key]) {
57
+ return // Already processed or processing
58
+ }
59
+
60
+ // Preemptively assign to avoid infinite recursion over bidirectional associations
61
+ const schema: SchemaObject & SemanticExtension = {
62
+ type: 'object',
63
+ properties: {},
64
+ required: [],
65
+ }
66
+ this.memorySchemas[entity.key] = schema
67
+ const schemaKey = this.generateSchemaKey(entity)
68
+ this.memoryNames[entity.key] = schemaKey
69
+ if (entity.info.displayName) {
70
+ schema.title = entity.info.displayName
71
+ }
72
+ if (entity.info.description) {
73
+ schema.description = entity.info.description
74
+ }
75
+
76
+ if (entity.semantics.length > 0) {
77
+ schema['x-api-now-semantics'] = {}
78
+ for (const semantic of entity.semantics) {
79
+ schema['x-api-now-semantics'][getSemanticName(semantic.id)] = semantic.config ? semantic.config : {}
80
+ }
81
+ }
82
+
83
+ const required: string[] = []
84
+
85
+ for (const prop of entity.properties) {
86
+ if (prop.required && !prop.readOnly) {
87
+ required.push(prop.info.name || prop.key)
88
+ }
89
+ if (!schema.properties) {
90
+ schema.properties = {}
91
+ }
92
+ const webBindings = prop.readBinding('web') as PropertyWebBindings | undefined
93
+ if (webBindings?.hidden) {
94
+ continue
95
+ }
96
+ schema.properties[prop.info.name || prop.key] = this.mapPropertyBase(prop, webBindings)
97
+ }
98
+
99
+ for (const assoc of entity.associations) {
100
+ const bindings = assoc.readBinding('web') as AssociationWebBindings | undefined
101
+ if (bindings?.hidden) {
102
+ continue
103
+ }
104
+
105
+ const targets = Array.from(assoc.listTargets())
106
+ if (targets.length === 0) continue
107
+
108
+ const linked = assoc.schema?.linked === true
109
+ const targetRefs: (SchemaObject | ReferenceObject)[] = []
110
+
111
+ for (const targetEntity of targets) {
112
+ if (linked) {
113
+ // When an entity is linked then we treat it as a regular property, which value is a key to
114
+ // the target entity. The consuming application has to construct the endpoint manually.
115
+ const targetName = targetEntity.info.displayName || targetEntity.info.name || targetEntity.key
116
+ targetRefs.push({
117
+ type: 'string',
118
+ description: `The ID of the linked ${targetName}.`,
119
+ })
120
+ } else {
121
+ // If not linked, embed the resource as a reference to the schema.
122
+ if (targetEntity !== entity) {
123
+ this.generateEntity(targetEntity)
124
+ }
125
+ targetRefs.push({ $ref: `#/components/schemas/${this.generateSchemaKey(targetEntity)}` })
126
+ }
127
+ }
128
+
129
+ let assocSchema: SchemaObject | ReferenceObject
130
+ if (targetRefs.length > 1) {
131
+ const unionType = assoc.schema?.unionType || 'anyOf'
132
+ if (unionType === 'oneOf') {
133
+ assocSchema = { oneOf: targetRefs }
134
+ } else if (unionType === 'allOf') {
135
+ assocSchema = { allOf: targetRefs }
136
+ } else {
137
+ assocSchema = { anyOf: targetRefs }
138
+ }
139
+ } else {
140
+ assocSchema = targetRefs[0]
141
+ }
142
+
143
+ const propName = assoc.info.name || assoc.key
144
+ if (!schema.properties) {
145
+ schema.properties = {}
146
+ }
147
+
148
+ if (assoc.multiple) {
149
+ schema.properties[propName] = {
150
+ type: 'array',
151
+ items: assocSchema,
152
+ }
153
+ } else {
154
+ schema.properties[propName] = assocSchema
155
+ }
156
+ }
157
+
158
+ if (required.length > 0) {
159
+ schema.required = required
160
+ } else {
161
+ delete schema.required
162
+ }
163
+ const example = entity.toExample('application/json', {
164
+ // renderExamples: true,
165
+ renderMocked: false,
166
+ renderOptional: true,
167
+ })
168
+ if (example) {
169
+ if (typeof example === 'string') {
170
+ try {
171
+ schema.example = JSON.parse(example)
172
+ } catch {
173
+ schema.example = example
174
+ }
175
+ } else {
176
+ schema.example = example
177
+ }
178
+ }
179
+ }
180
+
181
+ private mapPropertyBase(prop: DomainProperty, webBindings?: PropertyWebBindings): SchemaObject | ReferenceObject {
182
+ const base: SchemaObject & SemanticExtension = {}
183
+
184
+ if (prop.readOnly) {
185
+ base.readOnly = true
186
+ }
187
+
188
+ if (prop.writeOnly) {
189
+ base.writeOnly = true
190
+ }
191
+
192
+ if (prop.deprecated) {
193
+ base.deprecated = true
194
+ }
195
+
196
+ if (prop.schema) {
197
+ if (prop.schema.minimum !== undefined) {
198
+ if (prop.schema.exclusiveMinimum) {
199
+ base.exclusiveMinimum = prop.schema.minimum
200
+ } else {
201
+ base.minimum = prop.schema.minimum
202
+ }
203
+ }
204
+ if (prop.schema.maximum !== undefined) {
205
+ if (prop.schema.exclusiveMaximum) {
206
+ base.exclusiveMaximum = prop.schema.maximum
207
+ } else {
208
+ base.maximum = prop.schema.maximum
209
+ }
210
+ }
211
+ if (prop.schema.pattern) {
212
+ base.pattern = prop.schema.pattern
213
+ }
214
+ if (prop.schema.enum) {
215
+ base.enum = [...prop.schema.enum]
216
+ }
217
+ if (prop.schema.defaultValue?.value !== undefined) {
218
+ base.default = prop.schema.defaultValue.value
219
+ }
220
+ if (prop.schema.examples && prop.schema.examples.length > 0) {
221
+ // AMF incorrectly ignores `examples` property in JSON Schema in OAS 3.1 version.
222
+ // A temporary workaround is to set the `example` property instead of `examples`.
223
+ // const examples: ExampleObject[] = []
224
+ // for (const example of prop.schema.examples) {
225
+ // const value: ExampleObject = {
226
+ // value: example,
227
+ // }
228
+ // examples.push(value)
229
+ // }
230
+ // base.examples = examples
231
+ base.example = prop.schema.examples[0]
232
+ }
233
+ }
234
+
235
+ if (prop.info.displayName) {
236
+ base.title = prop.info.displayName
237
+ }
238
+
239
+ if (prop.info.description) {
240
+ base.description = prop.info.description
241
+ }
242
+
243
+ if (prop.hasSemantic(SemanticType.Password)) {
244
+ base.format = 'password'
245
+ }
246
+
247
+ if (webBindings?.xml) {
248
+ base.xml = { ...webBindings.xml }
249
+ }
250
+
251
+ if (prop.semantics.length > 0) {
252
+ base['x-api-now-semantics'] = {}
253
+ for (const semantic of prop.semantics) {
254
+ if (!this.#hasFileUpload && (semantic.id === SemanticType.FileURL || semantic.id === SemanticType.ImageURL)) {
255
+ this.#hasFileUpload = true
256
+ }
257
+ base['x-api-now-semantics'][getSemanticName(semantic.id)] = semantic.config ? semantic.config : {}
258
+ }
259
+ }
260
+
261
+ switch (prop.type) {
262
+ case 'string':
263
+ base.type = 'string'
264
+ break
265
+ case 'number':
266
+ if (webBindings?.format === 'int32' || webBindings?.format === 'int64') {
267
+ base.type = 'integer'
268
+ } else {
269
+ base.type = 'number'
270
+ }
271
+ if (prop.schema?.multipleOf !== undefined) {
272
+ base.multipleOf = prop.schema.multipleOf
273
+ }
274
+ break
275
+ case 'boolean':
276
+ base.type = 'boolean'
277
+ break
278
+ case 'date':
279
+ base.type = 'string'
280
+ base.format = 'date'
281
+ break
282
+ case 'datetime':
283
+ base.type = 'string'
284
+ base.format = 'date-time'
285
+ break
286
+ case 'time':
287
+ base.type = 'string'
288
+ base.format = 'time'
289
+ break
290
+ case 'binary':
291
+ base.type = 'string'
292
+ if (webBindings?.format) {
293
+ base.format = webBindings.format
294
+ } else {
295
+ base.format = 'binary'
296
+ }
297
+ if (webBindings?.fileTypes && webBindings.fileTypes.length > 0) {
298
+ const typesStr = webBindings.fileTypes.join(', ')
299
+ // Standard JSON Schema keyword for media wrapping (single value string usually,
300
+ // but some tools handle comma separated)
301
+ base.contentMediaType = webBindings.fileTypes.length === 1 ? webBindings.fileTypes[0] : typesStr
302
+ // Vendor extension for tools supporting multiple explicit arrays
303
+ // ;(base as any)['x-file-types'] = webBindings.fileTypes
304
+ // Append to description so viewers can always see the requirements natively
305
+ const typesDesc = `**Allowed file types:** ${typesStr}`
306
+ base.description = base.description ? `${base.description}\n\n${typesDesc}` : typesDesc
307
+ }
308
+ break
309
+ default:
310
+ base.type = 'string' // fallback
311
+ }
312
+
313
+ if (prop.multiple) {
314
+ return {
315
+ type: 'array',
316
+ items: base,
317
+ }
318
+ }
319
+
320
+ return base
321
+ }
322
+ }