openapi_generate_typescript_fetch 0.1.0

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.
@@ -0,0 +1,1237 @@
1
+ <%=
2
+ Gen.output.config = Gen.x.cfg['ts_indentation']
3
+ Gen.x.generator_info
4
+ %>
5
+
6
+ import type {<%= Gen.x.schemas.import_types.join(', ') %>} from '../src/schemas.d.ts';
7
+
8
+ // Schema instance maker functions.
9
+
10
+ const fakeEncoded = 'passes isEncodedBodyType';
11
+ const failEncoded = 12345678;
12
+
13
+ // Simple types.
14
+ <%=
15
+ def make_name(schema, kind, name)
16
+ array = schema[kind]
17
+ raise ArgumentError, "No array in schema for #{kind}" if array.nil?
18
+ suffix = LuckyCase.pascal_case(kind.to_s)
19
+ array.push("make#{LuckyCase.pascal_case(name)}#{suffix}#{array.size}")
20
+ Gen.x.makers.functions.push(array.last)
21
+ end
22
+
23
+ def integerMultiple(multiple)
24
+ rem = multiple.is_a?(Integer) ? 0 : (multiple - multiple.truncate)
25
+ if rem > 0
26
+ warn("multipleOf value #{multiple} is not an integer, may cause precision issues")
27
+ # Determine what to multiply with to get an integer.
28
+ mm = 1.0 / rem
29
+ if mm - mm.truncate == 0
30
+ multiple *= mm
31
+ else
32
+ warn("multipleOf value #{multiple} has problematic fractional part")
33
+ multiple *= mm.truncate # Will fail tests.
34
+ end
35
+ end
36
+ multiple
37
+ end
38
+
39
+ def surround(value, is_integer, multipleOf)
40
+ return [ nil, nil, nil ] if value.nil?
41
+ return [ value - multipleOf, value, value + multipleOf ] unless multipleOf.nil?
42
+ return [ value - 1, value, value + 1 ] if is_integer
43
+ value = Float(value) unless value.is_a?(Float)
44
+ [ value.prev_float, value, value.next_float ]
45
+ end
46
+
47
+ out = []
48
+ todo = []
49
+ sis = OpenAPIArrangement::Schema.dependencies_first(Gen.doc)
50
+ sis.each do |si|
51
+ si.schema[:pass] = []
52
+ si.schema[:fail] = []
53
+ si.schema[:typefail] = []
54
+ case si.schema['type']
55
+ when 'object'
56
+ props = si.schema['properties'] || {}
57
+ pat_props = si.schema['patternProperties'] || {}
58
+ add_props = si.schema['additionalProperties']
59
+ if si.schema[:typefail].empty?
60
+ make_name(si.schema, :typefail, si.name)
61
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 1 as unknown as #{si.name}; }")
62
+ make_name(si.schema, :typefail, si.name)
63
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 'str' as unknown as #{si.name}; }")
64
+ make_name(si.schema, :typefail, si.name)
65
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return true as unknown as #{si.name}; }")
66
+ make_name(si.schema, :typefail, si.name)
67
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return null as unknown as #{si.name}; }")
68
+ make_name(si.schema, :typefail, si.name)
69
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return [] as unknown as #{si.name}; }")
70
+ end
71
+ if props.empty? && pat_props.empty? && (add_props.nil? || add_props == false)
72
+ make_name(si.schema, :pass, si.name)
73
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return {} as #{si.name}; }")
74
+ if add_props == false
75
+ make_name(si.schema, :fail, si.name)
76
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return { prop: 'invalid' } as #{si.name}; }")
77
+ end
78
+ next
79
+ end
80
+ unless si.schema.fetch('required', []).empty?
81
+ make_name(si.schema, :fail, si.name)
82
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return {} as #{si.name}; }")
83
+ end
84
+ todo.push(si)
85
+ when 'array'
86
+ if si.schema[:typefail].empty?
87
+ make_name(si.schema, :typefail, si.name)
88
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 1 as unknown as #{si.name}; }")
89
+ make_name(si.schema, :typefail, si.name)
90
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 'str' as unknown as #{si.name}; }")
91
+ make_name(si.schema, :typefail, si.name)
92
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return true as unknown as #{si.name}; }")
93
+ make_name(si.schema, :typefail, si.name)
94
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return null as unknown as #{si.name}; }")
95
+ make_name(si.schema, :typefail, si.name)
96
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return {} as unknown as #{si.name}; }")
97
+ end
98
+ min_items = si.schema.fetch('minItems', 0)
99
+ max_items = si.schema['maxItems']
100
+ min_contains = si.schema.fetch('minContains', 0)
101
+ max_contains = si.schema['maxContains']
102
+ max_contains = nil if !max_items.nil? && !max_contains.nil? && max_items < max_contains
103
+ prefix = si.schema['prefixItems']
104
+ unless prefix.nil?
105
+ prefix = prefix[0...max_items] if !max_items.nil? && max_items < prefix.size
106
+ prefix = prefix.map { |p| Gen.h.dereference(p) }
107
+ end
108
+ contains = Gen.h.dereference(si.schema['contains'])
109
+ items = Gen.h.dereference(si.schema['items'])
110
+ items = nil if !prefix.nil? && !max_items.nil? && prefix.size == max_items
111
+ unless items.nil?
112
+ max_items = [ max_items, max_contains ].compact.min if items == contains
113
+ end
114
+ alts = {
115
+ prefix: prefix || [],
116
+ items: items,
117
+ contains: contains,
118
+ max_contains: max_contains,
119
+ max_items: max_items
120
+ }
121
+ si.schema[:alts] = alts
122
+ # Handle size-based fails. Any type is ok as length is not within limits.
123
+ if min_items > 1
124
+ make_name(si.schema, :fail, si.name)
125
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { const a = []; a[#{min_items - 2}] = 1; return a as #{si.name}; }")
126
+ elsif min_items == 1
127
+ make_name(si.schema, :fail, si.name)
128
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return [] as #{si.name}; }")
129
+ elsif min_items.zero?
130
+ make_name(si.schema, :pass, si.name)
131
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return [] as #{si.name}; }")
132
+ end
133
+ unless max_items.nil?
134
+ make_name(si.schema, :fail, si.name)
135
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { const a = []; a[#{max_items}] = 0; return a as #{si.name}; }")
136
+ end
137
+ todo.push(si)
138
+ when 'string'
139
+ pat = si.schema['pattern']
140
+ min_len = si.schema['minLength']
141
+ unless min_len.nil?
142
+ if min_len.positive?
143
+ s = 'f' * (min_len - 1)
144
+ make_name(si.schema, :fail, si.name)
145
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return '#{s}'; }")
146
+ end
147
+ if pat.nil?
148
+ s = 's' * min_len
149
+ make_name(si.schema, :pass, si.name)
150
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return '#{s}'; }")
151
+ end
152
+ end
153
+ max_len = si.schema['maxLength']
154
+ unless max_len.nil?
155
+ s = 'f' * (max_len + 1)
156
+ make_name(si.schema, :fail, si.name)
157
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return '#{s}'; }")
158
+ if pat.nil?
159
+ s = 's' * max_len
160
+ make_name(si.schema, :pass, si.name)
161
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return '#{s}'; }")
162
+ end
163
+ end
164
+ if min_len.nil? && max_len.nil? && pat.nil?
165
+ s = 's'
166
+ make_name(si.schema, :pass, si.name)
167
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return '#{s}'; }")
168
+ end
169
+ unless pat.nil?
170
+ tp_path = %w[tests patterns]
171
+ tps = Gen.x.cfg.dig(*tp_path) || []
172
+ pt = tps.index { |p| p['pattern'] == pat && p['minLength'] == min_len && p['maxLength'] == max_len }
173
+ if pt.nil?
174
+ out.push("// No #{si.name} pattern #{pat} test data in configuration #{tp_path.join('.')}. No make functions.")
175
+ else
176
+ pt = tps[pt]
177
+ { pass: 'pass', fail: 'fail' }.each do |kind, src|
178
+ pt.fetch(src, []).each do |s|
179
+ make_name(si.schema, kind, si.name)
180
+ out.push("export function #{si.schema[kind].last}(): #{si.name} { return '#{s}'; }")
181
+ end
182
+ end
183
+ end
184
+ end
185
+ make_name(si.schema, :typefail, si.name)
186
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return false as unknown as #{si.name}; }")
187
+ make_name(si.schema, :typefail, si.name)
188
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 1 as unknown as #{si.name}; }")
189
+ make_name(si.schema, :typefail, si.name)
190
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return {} as unknown as #{si.name}; }")
191
+ make_name(si.schema, :typefail, si.name)
192
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return [] as unknown as #{si.name}; }")
193
+ when 'integer', 'number'
194
+ if si.schema[:native] == :integer
195
+ min_val = si.schema.fetch('minimum', si.schema['exclusiveMinimum'])
196
+ unless min_val.nil?
197
+ if min_val.negative?
198
+ min_val = min_val.truncate
199
+ else
200
+ min_val = (min_val - min_val.truncate > 0) ? min_val.truncate + 1 : min_val
201
+ end
202
+ end
203
+ max_val = si.schema.fetch('maximum', si.schema['exclusiveMaximum'])
204
+ max_val = max_val.truncate unless max_val.nil?
205
+ mo = si.schema.key('multipleOf') ? integerMultiple(si.schema['multipleOf'].abs) : nil
206
+ mins = surround(min_val, true, mo)
207
+ maxs = surround(max_val, true, mo)
208
+ if min_val.nil?
209
+ if max_val.nil?
210
+ unsafe = 0.5
211
+ else
212
+ unsafe = max_val - 0.5
213
+ end
214
+ else
215
+ if max_val.nil?
216
+ unsafe = min_val + 0.5
217
+ else
218
+ unsafe = (min_val < max_val) ? (0.5 * (max_val - min_val)).truncate + 0.1 : nil
219
+ end
220
+ end
221
+ else
222
+ min_val = si.schema.fetch('minimum', si.schema['exclusiveMinimum'])
223
+ max_val = si.schema.fetch('maximum', si.schema['exclusiveMaximum'])
224
+ mo = si.schema.key('multipleOf') ? si.schema['multipleOf'].abs : nil
225
+ mins = surround(min_val, false, mo)
226
+ maxs = surround(max_val, false, mo)
227
+ unsafe = nil
228
+ end
229
+ if si.schema.key?('exclusiveMinimum')
230
+ mins.shift
231
+ elsif si.schema.key?('minimum')
232
+ mins.pop
233
+ end
234
+ if si.schema.key?('exclusiveMaximum')
235
+ maxs.pop
236
+ elsif si.schema.key?('maximum')
237
+ maxs.shift
238
+ end
239
+ unless mins.first.nil?
240
+ make_name(si.schema, :fail, si.name)
241
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{mins.first}; }")
242
+ end
243
+ unless mins.last.nil?
244
+ make_name(si.schema, :pass, si.name)
245
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return #{mins.last}; }")
246
+ end
247
+ unless maxs.first.nil?
248
+ make_name(si.schema, :pass, si.name)
249
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return #{maxs.first}; }")
250
+ end
251
+ unless maxs.last.nil?
252
+ make_name(si.schema, :fail, si.name)
253
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{maxs.last}; }")
254
+ end
255
+ if mins.concat(maxs).compact.empty?
256
+ make_name(si.schema, :pass, si.name)
257
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return 0; }")
258
+ unless mo.nil?
259
+ make_name(si.schema, :fail, si.name)
260
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{(3 * mo) / 2}; }")
261
+ end
262
+ end
263
+ unless unsafe.nil?
264
+ make_name(si.schema, :fail, si.name)
265
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{unsafe}; }")
266
+ end
267
+ make_name(si.schema, :typefail, si.name)
268
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return false as unknown as #{si.name}; }")
269
+ make_name(si.schema, :typefail, si.name)
270
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return 'a' as unknown as #{si.name}; }")
271
+ make_name(si.schema, :typefail, si.name)
272
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return {} as unknown as #{si.name}; }")
273
+ make_name(si.schema, :typefail, si.name)
274
+ out.push("export function #{si.schema[:typefail].last}(): #{si.name} { return [] as unknown as #{si.name}; }")
275
+ when 'boolean'
276
+ make_name(si.schema, :pass, si.name)
277
+ out.push("export function #{si.schema[:pass].last}(): boolean { return true; }")
278
+ make_name(si.schema, :pass, si.name)
279
+ out.push("export function #{si.schema[:pass].last}(): boolean { return false; }")
280
+ make_name(si.schema, :typefail, si.name)
281
+ out.push("export function #{si.schema[:typefail].last}(): boolean { return 1 as unknown as boolean; }")
282
+ make_name(si.schema, :typefail, si.name)
283
+ out.push("export function #{si.schema[:typefail].last}(): boolean { return 'a' as unknown as boolean; }")
284
+ make_name(si.schema, :typefail, si.name)
285
+ out.push("export function #{si.schema[:typefail].last}(): boolean { return {} as unknown as boolean; }")
286
+ make_name(si.schema, :typefail, si.name)
287
+ out.push("export function #{si.schema[:typefail].last}(): boolean { return [] as unknown as boolean; }")
288
+ else
289
+ raise StandardError, "Unhandled type: #{si.schema['type']} #{si.schema}"
290
+ end
291
+ end
292
+ Gen.output.join(out)
293
+ %>
294
+
295
+ // Using these to construct arrays presumes that the maker and contains is-function work.
296
+ type Maker = () => any;
297
+ type Checker = (x: any) => boolean;
298
+
299
+ function makeArray(length: number, prefixMakers: Array<Maker>, itemMaker: Maker): Array<any> {
300
+ const result: Array<any> = [];
301
+ for (const m of prefixMakers) {
302
+ result.push(m());
303
+ if (result.length == length) break;
304
+ }
305
+ while (result.length < length) {
306
+ result.push(itemMaker());
307
+ }
308
+ return result;
309
+ }
310
+
311
+ function makeContainingArray(length: number, prefixMakers: Array<Maker>, itemMaker: Maker|null,
312
+ containsMaker: Maker, containsIs: Checker, minContains: number, maxContains: number): Array<any>
313
+ {
314
+ let contained = 0;
315
+ const result: Array<any> = [];
316
+ for (const m of prefixMakers) {
317
+ result.push(m());
318
+ if (containsIs(result[result.length - 1])) ++contained;
319
+ if (length <= result.length && minContains <= result.length) break;
320
+ }
321
+ if (itemMaker === null) {
322
+ while (contained < minContains) {
323
+ result.push(containsMaker());
324
+ ++contained;
325
+ }
326
+ while (result.length < length && contained < maxContains) {
327
+ result.push(containsMaker());
328
+ ++contained;
329
+ }
330
+ } else {
331
+ while (contained < minContains) {
332
+ result.push(containsMaker());
333
+ ++contained;
334
+ }
335
+ while (result.length < length && contained < maxContains) {
336
+ result.push(itemMaker());
337
+ if (containsIs(result[result.length - 1])) ++contained;
338
+ }
339
+ }
340
+ return result;
341
+ }
342
+
343
+ function replace(arr: Array<any>, index: number, maker: Maker): Array<any> {
344
+ arr[Math.min(index, arr.length)] = maker();
345
+ return arr;
346
+ }
347
+
348
+ // Complex types.
349
+ <%=
350
+ def other_type(cands)
351
+ makers = {
352
+ 'boolean' => '() => true',
353
+ 'number' => '() => 1.5',
354
+ 'integer' => '() => 2',
355
+ 'string' => '() => "str"',
356
+ 'object' => '() => ({})',
357
+ 'array' => '() => []'
358
+ }
359
+ makers.each do |type, maker|
360
+ return maker if !cands.index { |c| c['type'] == type }.nil?
361
+ end
362
+ return '() => null'
363
+ end
364
+
365
+ out = []
366
+ loop do
367
+ found = false
368
+ process = todo
369
+ todo = []
370
+ # What we need to do here is to gather a pass/fail function for each property.
371
+ process.each do |si|
372
+ case si.schema['type']
373
+ when 'object'
374
+ props = si.schema['properties'] || {}
375
+ pat_props = si.schema['patternProperties'] || {}
376
+ add_props = si.schema['additionalProperties']
377
+ all_props = [ props, pat_props ]
378
+ all_props.push({ unused: add_props }) if add_props.is_a?(Hash)
379
+ all_props.each do |ps|
380
+ ps.each_value do |prop|
381
+ schema = Gen.h.dereference(prop)
382
+ if prop[:pass].nil? && !schema[:pass].empty?
383
+ prop[:pass] = schema[:pass].first
384
+ found = true
385
+ end
386
+ if prop[:fail].nil? && !schema[:fail].empty?
387
+ prop[:fail] = schema[:fail].first
388
+ end
389
+ end
390
+ end
391
+ reqd = si.schema.fetch('required', []).sort
392
+ passes = {}
393
+ reqd.each { |name| passes[name] = props[name][:pass] if props[name].key?(:pass) }
394
+ pass_lines = passes.keys.map { |k| "#{k}: #{passes[k]}()" }
395
+ if si.schema[:reqd_done]
396
+ remains = false
397
+ # Cover all uncovered optional ones in turn. Flag as covered.
398
+ # Explicitly named optional ones.
399
+ props.each do |name, prop|
400
+ next if reqd.include?(name)
401
+ unless prop[:pass].nil? || prop[:pass_done].nil?
402
+ lines = [ "#{name}: #{prop[:pass]}" ].concat(pass_lines)
403
+ make_name(si.schema, :pass, si.name)
404
+ s = <<EOB
405
+ export function #{si.schema[:pass].last}(): #{si.name} {
406
+ return {
407
+ #{lines.join(",\n")}
408
+ } as #{si.name};
409
+ }
410
+ EOB
411
+ out.push(s)
412
+ prop[:pass_done] = true
413
+ found = true
414
+ end
415
+ unless prop[:fail].nil? || prop[:fail_done].nil?
416
+ lines = [ "#{name}: #{prop[:fail]}" ].concat(pass_lines)
417
+ make_name(si.schema, :fail, si.name)
418
+ s = <<EOB
419
+ export function #{si.schema[:fail].last}(): #{si.name} {
420
+ return {
421
+ #{lines.join(",\n")}
422
+ } as #{si.name};
423
+ }
424
+ EOB
425
+ out.push(s)
426
+ prop[:fail_done] = true
427
+ found = true
428
+ end
429
+ remains = remains || prop[:fail_done].nil? || prop[:pass_done].nil?
430
+ end
431
+ # pattern properties. Required string that passes.
432
+ test_patterns = Gen.x.cfg.dig('tests', 'patterns') || []
433
+ common_fails = Set.new
434
+ min_length = test_patterns.map { |x| x['minLength'] }.compact.min
435
+ max_length = test_patterns.map { |x| x['maxLength'] }.compact.max
436
+ pats = {}
437
+ test_patterns.each do |p|
438
+ pats[p['pattern']] = {
439
+ pass: p['pass'],
440
+ fail: p['fail']
441
+ }
442
+ common_fails = common_fails & p['fail']
443
+ end
444
+ pat_props.each do |pat, prop|
445
+ name = (pats.dig(pat, 'pass') || []).first
446
+ next if name.nil?
447
+ unless prop[:pass].nil? || prop[:pass_done].nil?
448
+ lines = [ "#{name}: #{prop[:pass]}" ].concat(pass_lines)
449
+ make_name(si.schema, :pass, si.name)
450
+ s = <<EOB
451
+ export function #{si.schema[:pass].last}(): #{si.name} {
452
+ return {
453
+ #{lines.join(",\n")}
454
+ } as #{si.name};
455
+ }
456
+ EOB
457
+ out.push(s)
458
+ prop[:pass_done] = true
459
+ found = true
460
+ end
461
+ unless prop[:fail].nil? || prop[:fail_done].nil?
462
+ lines = [ "#{name}: #{prop[:fail]}" ].concat(pass_lines)
463
+ make_name(si.schema, :fail, si.name)
464
+ s = <<EOB
465
+ export function #{si.schema[:fail].last}(): #{si.name} {
466
+ return {
467
+ #{lines.join(",\n")}
468
+ } as #{si.name};
469
+ }
470
+ EOB
471
+ out.push(s)
472
+ prop[:fail_done] = true
473
+ found = true
474
+ end
475
+ remains = remains || prop[:fail_done].nil? || prop[:pass_done].nil?
476
+ end
477
+ name = nil
478
+ if pat_props.empty?
479
+ name = 'f' * (props.keys.map(&:size).max + 1)
480
+ else
481
+ name = common_fails.to_a.reject { |x| props.key?(x) }.first
482
+ name = nil if props.key?(name)
483
+ end
484
+ if name.nil?
485
+ warn("#{si.name} no name candidate for additional property tests")
486
+ si.schema[:ap_fail_done] = true
487
+ si.schema[:ap_pass_done] = true
488
+ else
489
+ if add_props.is_a?(Hash) # Only this accepted.
490
+ unless add_props[:fail].nil? || si.schema[:ap_fail_done].nil?
491
+ lines = [ "#{name}: #{add_props[:fail]}" ].concat(pass_lines)
492
+ make_name(si.schema, :fail, si.name)
493
+ s = <<EOB
494
+ export function #{si.schema[:fail].last}(): #{si.name} {
495
+ return {
496
+ #{lines.join(",\n")}
497
+ } as #{si.name};
498
+ }
499
+ EOB
500
+ out.push(s)
501
+ si.schema[:ap_fail_done] = true
502
+ found = true
503
+ end
504
+ unless add_props[:pass].nil? || si.schema[:ap_pass_done].nil?
505
+ lines = [ "#{name}: #{add_props[:pass]}" ].concat(pass_lines)
506
+ make_name(si.schema, :pass, si.name)
507
+ s = <<EOB
508
+ export function #{si.schema[:pass].last}(): #{si.name} {
509
+ return {
510
+ #{lines.join(",\n")}
511
+ } as #{si.name};
512
+ }
513
+ EOB
514
+ out.push(s)
515
+ si.schema[:ap_pass_done] = true
516
+ found = true
517
+ end
518
+ remains = remains || si.schema[:ap_fail_done].nil? || si.schema[:ap_pass_done].nil?
519
+ elsif add_props.nil? || add_props == true # Anything goes.
520
+ si.schema[:ap_fail_done] = true
521
+ unless si.schema[:ap_pass_done].nil?
522
+ lines = [ "#{name}: true" ].concat(pass_lines)
523
+ make_name(si.schema, :pass, si.name)
524
+ s = <<EOB
525
+ export function #{si.schema[:pass].last}(): #{si.name} {
526
+ return {
527
+ #{lines.join(",\n")}
528
+ } as #{si.name};
529
+ }
530
+ EOB
531
+ out.push(s)
532
+ si.schema[:ap_pass_done] = true
533
+ found = true
534
+ end
535
+ else # False, only failure.
536
+ si.schema[:ap_pass_done] = true
537
+ unless si.schema[:ap_fail_done].nil?
538
+ lines = [ "#{name}: false" ].concat(pass_lines)
539
+ make_name(si.schema, :fail, si.name)
540
+ s = <<EOB
541
+ export function #{si.schema[:fail].last}(): #{si.name} {
542
+ return {
543
+ #{lines.join(",\n")}
544
+ } as #{si.name};
545
+ }
546
+ EOB
547
+ out.push(s)
548
+ si.schema[:ap_fail_done] = true
549
+ si.schema[:unknown_name] = name
550
+ found = true
551
+ end
552
+ end
553
+ end
554
+ todo.push(si) if remains
555
+ end
556
+ # Required property make functions.
557
+ if passes.size < reqd.size
558
+ todo.push(si)
559
+ next
560
+ end
561
+ si.schema[:reqd_done] = true
562
+ todo.push(si)
563
+ next if reqd.empty?
564
+ # We have full required property passes, make pass function.
565
+ make_name(si.schema, :pass, si.name)
566
+ s = <<EOB
567
+ export function #{si.schema[:pass].last}(): #{si.name} {
568
+ return {
569
+ #{pass_lines.join(",\n")}
570
+ } as #{si.name};
571
+ }
572
+ EOB
573
+ out.push(s)
574
+ # Each required property missing in turn, others present and pass.
575
+ passes.keys.each do |missing|
576
+ others = {}.merge(passes)
577
+ others.delete(missing)
578
+ make_name(si.schema, :fail, si.name)
579
+ s = <<EOB
580
+ export function #{si.schema[:fail].last}(): #{si.name} {
581
+ return {
582
+ #{others.keys.map { |k| "#{k}: #{others[k]}()" }.join(",\n")}
583
+ } as #{si.name};
584
+ }
585
+ EOB
586
+ out.push(s)
587
+ end
588
+ # Each required property failing if possible in turn, others present and pass.
589
+ passes.keys.each do |failing|
590
+ fail = props[failing][:fail]
591
+ next if fail.nil?
592
+ lines = {}.merge(passes)
593
+ lines.delete(failing)
594
+ lines = lines.keys.map { |k| "#{k}: #{passes[k]}()" }
595
+ lines.push("#{failing}: #{fail}()")
596
+ make_name(si.schema, :fail, si.name)
597
+ s = <<EOB
598
+ export function #{si.schema[:fail].last}(): #{si.name} {
599
+ return {
600
+ #{lines.join(",\n")}
601
+ } as #{si.name};
602
+ }
603
+ EOB
604
+ out.push(s)
605
+ end
606
+ when 'array'
607
+ alts = si.schema[:alts]
608
+ max_items = alts[:max_items]
609
+ min_items = si.schema.fetch('minItems', 0)
610
+ if alts[:prefix].empty? && alts[:contains].nil?
611
+ # Simple array with just items.
612
+ items = alts[:items]
613
+ if items[:pass].empty?
614
+ todo.push(si) # Not ready yet.
615
+ next
616
+ end
617
+ counts = [ min_items + 1, max_items.nil? ? nil : max_items - 1 ].compact.reject { |k| k <= min_items }.reject { |k| (max_items || (min_items + 1)) < k }
618
+ counts.each do |k|
619
+ make_name(si.schema, :pass, si.name)
620
+ s = <<EOB
621
+ export function #{si.schema[:pass].last}(): #{si.name} {
622
+ const a: #{si.name} = [];
623
+ for (let k = 0; k < #{k}; ++k) a[k] = #{items[:pass].first}();
624
+ return a;
625
+ }
626
+ EOB
627
+ out.push(s)
628
+ end
629
+ fn = items[:fail].first unless items[:fail].empty?
630
+ fn = items[:typefail].first unless fn.nil? && items[:typefail].empty?
631
+ unless fn.nil?
632
+ counts.each do |k|
633
+ make_name(si.schema, :fail, si.name)
634
+ s = <<EOB
635
+ export function #{si.schema[:fail].last}(): #{si.name} {
636
+ const a: #{si.name} = [];
637
+ for (let k = 0; k < #{k}; ++k) a[k] = #{fn}();
638
+ return a;
639
+ }
640
+ EOB
641
+ out.push(s)
642
+ end
643
+ end
644
+ next
645
+ end
646
+ max_contains = alts[:max_contains]
647
+ miss = (alts.dig(:items, :pass) || []).empty? || (alts.dig(:contains, :pass) || []).empty?
648
+ unless miss
649
+ miss = (alts[:prefix] || []).index { |p| p[:pass].empty? }
650
+ end
651
+ if miss.nil?
652
+ # All schemas have pass maker function.
653
+ # Assume fail makers are present as they are usually simple when possible.
654
+ sizes = [ min_items, min_contains, schemas.size, max_contains, max_items ].compact.sort!.uniq
655
+ pp = alts[:prefix].nil? ? '[]' : "[ #{alts[:prefix].map { |p| "#{p[:pass].first}()" }.join (', ')} ]"
656
+ sizes.each do |target|
657
+ # All pass.
658
+ if alts[:contains].nil?
659
+ ip = alts[:items].nil? ? '() => 1' : "#{alts[:items][:pass].first}()"
660
+ ma = "makeArray(#{target}, #{pp}, #{ip})"
661
+ else
662
+ ip = alts[:items].nil? ? 'null' : "#{alts[:items][:pass].first}()"
663
+ ma = "makeContainingArray(#{target}, #{pp}, #{ip}, #{alts[:contains][:pass].first}, #{alts[:contains][:is]}, #{min_contains}, #{max_contains || target})"
664
+ end
665
+ make_name(si.schema, :pass, si.name)
666
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return #{ma} as #{si.name}; }")
667
+ # Each fails in turn.
668
+ next unless target == sizes.max
669
+ target.times do |idx|
670
+ if idx < pp.size
671
+ m = other_type([ alts[:prefix][idx], alts[:contains] ].compact)
672
+ make_name(si.schema, :fail, si.name)
673
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return replace(#{ma}, #{idx}, #{m}) as #{si.name}; }")
674
+ else
675
+ m = other_type([ alts[:items], alts[:contains] ].compact)
676
+ make_name(si.schema, :fail, si.name)
677
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return replace(#{ma}, #{idx}, #{m}) as #{si.name}; }")
678
+ end
679
+ end
680
+ end
681
+ unless alts[:contains].nil?
682
+ # Contains fails need special maker calls.
683
+ unless max_contains.nil?
684
+ # Too many contains fail, set minContains > max_contains
685
+ len = max_contains + 1
686
+ ma = "makeContainingArray(#{min_items}, #{pp}, null, #{alts[:contains][:pass].first}, #{alts[:contains][:is]}, #{len}, #{len})"
687
+ make_name(si.schema, :fail, si.name)
688
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{ma} as #{si.name}; }")
689
+ # Exactly max_contains pass, minContains == maxContains == max_contains
690
+ len = max_contains
691
+ ma = "makeContainingArray(#{min_items}, #{pp}, null, #{alts[:contains][:pass].first}, #{alts[:contains][:is]}, #{len}, #{len})"
692
+ make_name(si.schema, :pass, si.name)
693
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return #{ma} as #{si.name}; }")
694
+ end
695
+ unless min_contains.zero?
696
+ certain_mismatch = alts.fetch(:prefix, []).count { |s| s[:type] != contains['type'] }
697
+ if alts.fetch(:prefix, []).size - certain_mismatch < min_contains
698
+ # Too few contains fail, if applicable and possible. maxContains < min_contains
699
+ ip = alts[:items].nil? ? other_type([ contains ]) : "#{alts[:items][:pass].first}()"
700
+ len = min_contains - 1
701
+ ma = "makeContainingArray(#{min_items}, #{pp}, #{ip}, #{alts[:contains][:pass].first}, #{alts[:contains][:is]}, #{len}, #{len})"
702
+ make_name(si.schema, :fail, si.name)
703
+ out.push("export function #{si.schema[:fail].last}(): #{si.name} { return #{ma} as #{si.name}; }")
704
+ end
705
+ if min_items <= min_contains + certain_mismatch
706
+ # Min contains pass, minContains == maxContains == min_contains
707
+ len = min_contains
708
+ ma = "makeContainingArray(#{min_items}, #{pp}, () => null, #{alts[:contains][:pass].first}, #{alts[:contains][:is]}, #{len}, #{len})"
709
+ make_name(si.schema, :pass, si.name)
710
+ out.push("export function #{si.schema[:pass].last}(): #{si.name} { return #{ma} as #{si.name}; }")
711
+ end
712
+ end
713
+ end
714
+ si.schema[:type_done] = true
715
+ end
716
+ todo.push(si) unless si.schema[:type_done]
717
+ end
718
+ end
719
+ unless found
720
+ warn("Failed to generate maker functions for types:\n#{todo.map(&:name).sort!.join("\n")}")
721
+ break
722
+ end
723
+ end
724
+ Gen.output.join(out)
725
+ %>
726
+
727
+ // Operation parameter type makers.
728
+ <%=
729
+ out = []
730
+ Gen.doc['paths'].each do |path, path_item_object|
731
+ oos = OpenAPISourceTools::ApiObjects.operation_objects(path_item_object)
732
+ oos.each do |method, operation_object|
733
+ operation_object[:pass] = []
734
+ operation_object[:fail] = []
735
+ operation_object[:typefail] = []
736
+ operation_object[:throw] = []
737
+ if operation_object[:parameterless]
738
+ make_name(operation_object, :pass, operation_object[:args_name])
739
+ out.push("export function #{operation_object[:pass].last}(): #{operation_object[:args_name]} { return {} as #{operation_object[:args_name]}; }")
740
+ make_name(operation_object, :typefail, operation_object[:args_name])
741
+ out.push("export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} { return 1 as unknown as #{operation_object[:args_name]}; }")
742
+ make_name(operation_object, :typefail, operation_object[:args_name])
743
+ out.push("export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} { return 'str' as unknown as #{operation_object[:args_name]}; }")
744
+ make_name(operation_object, :typefail, operation_object[:args_name])
745
+ out.push("export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} { return true as unknown as #{operation_object[:args_name]}; }")
746
+ make_name(operation_object, :typefail, operation_object[:args_name])
747
+ out.push("export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} { return null as unknown as #{operation_object[:args_name]}; }")
748
+ make_name(operation_object, :typefail, operation_object[:args_name])
749
+ out.push("export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} { return [] as unknown as #{operation_object[:args_name]}; }")
750
+ next
751
+ end
752
+ paraschemas = operation_object[:paraschemas]
753
+ commons = {}
754
+ [ :pass, :fail, :typefail, 'missing' ].each do |kind|
755
+ paraschemas.size.times do |chosen|
756
+ param_makers = []
757
+ category = kind
758
+ paraschemas.size.times do |k|
759
+ ps = paraschemas[k]
760
+ schema = ps[:schema]
761
+ req = ps[:param]['required']
762
+ needed = :pass
763
+ if k == chosen
764
+ needed = kind
765
+ if kind == 'missing'
766
+ if req
767
+ needed = :typefail unless schema[:typefail].empty?
768
+ needed = :fail unless schema[:fail].empty?
769
+ category = needed
770
+ else
771
+ param_makers.push(nil)
772
+ next
773
+ end
774
+ end
775
+ end
776
+ m = schema[needed].first
777
+ break if m.nil?
778
+ param_makers.push({ maker: m, param: ps[:param] })
779
+ end
780
+ next if param_makers.size < paraschemas.size
781
+ common = param_makers.compact.map { |pm| "#{pm[:param][:name]}: #{pm[:maker]}()" }
782
+ commons[common.sort.join(';')] = { common: common, category: category }
783
+ end
784
+ end
785
+ commons.each_value do |cc|
786
+ common = cc[:common]
787
+ category = cc[:category]
788
+ req_body = operation_object['requestBody']
789
+ if req_body.nil?
790
+ make_name(operation_object, category, operation_object[:args_name])
791
+ s = <<EOB
792
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
793
+ return {
794
+ #{common.join(",\n")}
795
+ } as unknown as #{operation_object[:args_name]};
796
+ }
797
+ EOB
798
+ out.push(s)
799
+ next
800
+ end
801
+ body_types = req_body[:body_types]
802
+ req = req_body.fetch('required', false)
803
+ if req
804
+ if category == :pass
805
+ # Missing required body fail because of missing body.
806
+ make_name(operation_object, :fail, operation_object[:args_name])
807
+ s = <<EOB
808
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
809
+ return {
810
+ #{common.join(",\n")}
811
+ } as unknown as #{operation_object[:args_name]};
812
+ }
813
+ EOB
814
+ out.push(s)
815
+ else
816
+ # Body is present but fails because of other errors.
817
+ if body_types.key?('any')
818
+ lines = [].concat(common, [ "body: {}" ])
819
+ else
820
+ lines = common
821
+ body_types.each do |btype, bschema|
822
+ bm = bschema[:pass].first
823
+ next if bm.nil?
824
+ lines = [].concat(common, [ "body#{btype}: #{bm}()" ])
825
+ break
826
+ end
827
+ end
828
+ make_name(operation_object, category, operation_object[:args_name])
829
+ s = <<EOB
830
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
831
+ return {
832
+ #{lines.join(",\n")}
833
+ } as unknown as #{operation_object[:args_name]};
834
+ }
835
+ EOB
836
+ out.push(s)
837
+ end
838
+ end
839
+ next unless category == :pass
840
+ # Passes for each body type property present at a time.
841
+ body_types.each do |btype, bschema|
842
+ next if btype == 'any'
843
+ bm = bschema[:pass].first
844
+ next if bm.nil?
845
+ # Pass for type-specific body name.
846
+ make_name(operation_object, category, operation_object[:args_name])
847
+ lines = [].concat(common, [ "body#{btype}: #{bm}()" ])
848
+ s = <<EOB
849
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
850
+ return {
851
+ #{lines.join(",\n")}
852
+ } as unknown as #{operation_object[:args_name]};
853
+ }
854
+ EOB
855
+ out.push(s)
856
+ # Pass for type-specific body name and encoded present.
857
+ make_name(operation_object, category, operation_object[:args_name])
858
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "encoded: fakeEncoded" ])
859
+ s = <<EOB
860
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
861
+ return {
862
+ #{lines.join(",\n")}
863
+ } as unknown as #{operation_object[:args_name]};
864
+ }
865
+ EOB
866
+ out.push(s)
867
+ # Fail for type-specific body name and invalid encoded present.
868
+ make_name(operation_object, :fail, operation_object[:args_name])
869
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "encoded: failEncoded" ])
870
+ s = <<EOB
871
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
872
+ return {
873
+ #{lines.join(",\n")}
874
+ } as unknown as #{operation_object[:args_name]};
875
+ }
876
+ EOB
877
+ out.push(s)
878
+ # Pass for generic body.
879
+ make_name(operation_object, category, operation_object[:args_name])
880
+ lines = [].concat(common, [ "body: #{bm}()" ])
881
+ s = <<EOB
882
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
883
+ return {
884
+ #{lines.join(",\n")}
885
+ } as unknown as #{operation_object[:args_name]};
886
+ }
887
+ EOB
888
+ out.push(s)
889
+ # Pass for generic body and encoded present.
890
+ make_name(operation_object, category, operation_object[:args_name])
891
+ lines = [].concat(common, [ "body: #{bm}()", "encoded: fakeEncoded" ])
892
+ s = <<EOB
893
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
894
+ return {
895
+ #{lines.join(",\n")}
896
+ } as unknown as #{operation_object[:args_name]};
897
+ }
898
+ EOB
899
+ out.push(s)
900
+ # Fail for generic body and invalid encoded present.
901
+ make_name(operation_object, :fail, operation_object[:args_name])
902
+ lines = [].concat(common, [ "body: #{bm}()", "encoded: failEncoded" ])
903
+ s = <<EOB
904
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
905
+ return {
906
+ #{lines.join(",\n")}
907
+ } as unknown as #{operation_object[:args_name]};
908
+ }
909
+ EOB
910
+ out.push(s)
911
+ # Pass for two body fields set to same object instance.
912
+ make_name(operation_object, category, operation_object[:args_name])
913
+ lines = [].concat(common, [ "body#{btype}: b", "body: b" ])
914
+ s = <<EOB
915
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
916
+ const b = #{bm}();
917
+ return {
918
+ #{lines.join(",\n")}
919
+ } as unknown as #{operation_object[:args_name]};
920
+ }
921
+ EOB
922
+ out.push(s)
923
+ # Pass for two body fields set to same object instance and encoded present.
924
+ make_name(operation_object, category, operation_object[:args_name])
925
+ lines = [].concat(common, [ "body#{btype}: b", "body: b", "encoded: fakeEncoded" ])
926
+ s = <<EOB
927
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
928
+ const b = #{bm}();
929
+ return {
930
+ #{lines.join(",\n")}
931
+ } as unknown as #{operation_object[:args_name]};
932
+ }
933
+ EOB
934
+ out.push(s)
935
+ # Fail for two body fields set to same object instance and invalid encoded present.
936
+ make_name(operation_object, :fail, operation_object[:args_name])
937
+ lines = [].concat(common, [ "body#{btype}: b", "body: b", "encoded: failEncoded" ])
938
+ s = <<EOB
939
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
940
+ const b = #{bm}();
941
+ return {
942
+ #{lines.join(",\n")}
943
+ } as unknown as #{operation_object[:args_name]};
944
+ }
945
+ EOB
946
+ out.push(s)
947
+ # Only throws for sure since category is :pass.
948
+ # Throw for two body fields set to different object instances.
949
+ make_name(operation_object, :throw, operation_object[:args_name])
950
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "body: #{bm}()" ])
951
+ s = <<EOB
952
+ export function #{operation_object[:throw].last}(): #{operation_object[:args_name]} {
953
+ return {
954
+ #{lines.join(",\n")}
955
+ } as unknown as #{operation_object[:args_name]};
956
+ }
957
+ EOB
958
+ out.push(s)
959
+ # Pass for two body fields set to different object instances, with encoded overriding.
960
+ make_name(operation_object, :pass, operation_object[:args_name])
961
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "body: #{bm}()", "encoded: fakeEncoded" ])
962
+ s = <<EOB
963
+ export function #{operation_object[:pass].last}(): #{operation_object[:args_name]} {
964
+ return {
965
+ #{lines.join(",\n")}
966
+ } as unknown as #{operation_object[:args_name]};
967
+ }
968
+ EOB
969
+ out.push(s)
970
+ # Fail for two body fields set to different object instances, with invalid encoded.
971
+ make_name(operation_object, :fail, operation_object[:args_name])
972
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "body: #{bm}()", "encoded: failEncoded" ])
973
+ s = <<EOB
974
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
975
+ return {
976
+ #{lines.join(",\n")}
977
+ } as unknown as #{operation_object[:args_name]};
978
+ }
979
+ EOB
980
+ out.push(s)
981
+ end
982
+ if body_types.key?('any')
983
+ # Any type body pass.
984
+ make_name(operation_object, category, operation_object[:args_name])
985
+ lines = [].concat(common, [ "body: {}" ])
986
+ s = <<EOB
987
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
988
+ return {
989
+ #{lines.join(",\n")}
990
+ } as unknown as #{operation_object[:args_name]};
991
+ }
992
+ EOB
993
+ out.push(s)
994
+ # Any type body pass, with encoded body.
995
+ make_name(operation_object, category, operation_object[:args_name])
996
+ lines = [].concat(common, [ "body: {}", "encoded: fakeEncoded" ])
997
+ s = <<EOB
998
+ export function #{operation_object[category].last}(): #{operation_object[:args_name]} {
999
+ return {
1000
+ #{lines.join(",\n")}
1001
+ } as unknown as #{operation_object[:args_name]};
1002
+ }
1003
+ EOB
1004
+ out.push(s)
1005
+ # Any type body pass, with invalid encoded body.
1006
+ make_name(operation_object, :fail, operation_object[:args_name])
1007
+ lines = [].concat(common, [ "body: {}", "encoded: failEncoded" ])
1008
+ s = <<EOB
1009
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
1010
+ return {
1011
+ #{lines.join(",\n")}
1012
+ } as unknown as #{operation_object[:args_name]};
1013
+ }
1014
+ EOB
1015
+ out.push(s)
1016
+ else
1017
+ # Fail for generic body with each type.
1018
+ body_types.each do |btype, bschema|
1019
+ bm = bschema[:fail].first
1020
+ next if bm.nil?
1021
+ make_name(operation_object, :fail, operation_object[:args_name])
1022
+ lines = [].concat(common, [ "body: #{bm}()" ])
1023
+ s = <<EOB
1024
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
1025
+ return {
1026
+ #{lines.join(",\n")}
1027
+ } as unknown as #{operation_object[:args_name]};
1028
+ }
1029
+ EOB
1030
+ out.push(s)
1031
+ # Pass with encoded present.
1032
+ make_name(operation_object, :pass, operation_object[:args_name])
1033
+ lines = [].concat(common, [ "body: #{bm}()", "encoded: fakeEncoded" ])
1034
+ s = <<EOB
1035
+ export function #{operation_object[:pass].last}(): #{operation_object[:args_name]} {
1036
+ return {
1037
+ #{lines.join(",\n")}
1038
+ } as unknown as #{operation_object[:args_name]};
1039
+ }
1040
+ EOB
1041
+ out.push(s)
1042
+ # Fail with invalid encoded present.
1043
+ make_name(operation_object, :fail, operation_object[:args_name])
1044
+ lines = [].concat(common, [ "body: #{bm}()", "encoded: failEncoded" ])
1045
+ s = <<EOB
1046
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
1047
+ return {
1048
+ #{lines.join(",\n")}
1049
+ } as unknown as #{operation_object[:args_name]};
1050
+ }
1051
+ EOB
1052
+ out.push(s)
1053
+ end
1054
+ end
1055
+ # Fails for each specific type body property present at a time.
1056
+ body_types.each do |btype, bschema|
1057
+ next if btype == 'any'
1058
+ bm = bschema[:fail].first
1059
+ next if bm.nil?
1060
+ make_name(operation_object, :fail, operation_object[:args_name])
1061
+ lines = [].concat(common, [ "body#{btype}: #{bm}()" ])
1062
+ s = <<EOB
1063
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
1064
+ return {
1065
+ #{lines.join(",\n")}
1066
+ } as unknown as #{operation_object[:args_name]};
1067
+ }
1068
+ EOB
1069
+ out.push(s)
1070
+ # Same with encoded present.
1071
+ make_name(operation_object, :pass, operation_object[:args_name])
1072
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "encoded: fakeEncoded" ])
1073
+ s = <<EOB
1074
+ export function #{operation_object[:pass].last}(): #{operation_object[:args_name]} {
1075
+ return {
1076
+ #{lines.join(",\n")}
1077
+ } as unknown as #{operation_object[:args_name]};
1078
+ }
1079
+ EOB
1080
+ out.push(s)
1081
+ # Fail with invalid encoded present.
1082
+ make_name(operation_object, :fail, operation_object[:args_name])
1083
+ lines = [].concat(common, [ "body#{btype}: #{bm}()", "encoded: failEncoded" ])
1084
+ s = <<EOB
1085
+ export function #{operation_object[:fail].last}(): #{operation_object[:args_name]} {
1086
+ return {
1087
+ #{lines.join(",\n")}
1088
+ } as unknown as #{operation_object[:args_name]};
1089
+ }
1090
+ EOB
1091
+ out.push(s)
1092
+ end
1093
+ # Fails for two body members with different objects.
1094
+ btypes = body_types.keys.reject { |k| k == 'any' }.sort!
1095
+ btypes.size.times do |idx|
1096
+ bschema = body_types[btypes[idx]]
1097
+ bm = bschema[:pass].first
1098
+ next if bm.nil?
1099
+ 0.upto(idx - 1) do |k|
1100
+ kschema = body_types[btypes[k]]
1101
+ km = kschema[:pass].first
1102
+ next if km.nil?
1103
+ make_name(operation_object, :throw, operation_object[:args_name])
1104
+ lines = [].concat(common, [
1105
+ "body#{btypes[k]}: #{km}()",
1106
+ "body#{btypes[idx]}: #{bm}()"
1107
+ ])
1108
+ s = <<EOB
1109
+ export function #{operation_object[:throw].last}(): #{operation_object[:args_name]} {
1110
+ return {
1111
+ #{lines.join(",\n")}
1112
+ } as unknown as #{operation_object[:args_name]};
1113
+ }
1114
+ EOB
1115
+ out.push(s)
1116
+ end
1117
+ end
1118
+ end
1119
+ make_name(operation_object, :typefail, operation_object[:args_name])
1120
+ s = <<EOB
1121
+ export function #{operation_object[:typefail].last}(): #{operation_object[:args_name]} {
1122
+ return 1 as unknown as #{operation_object[:args_name]};
1123
+ }
1124
+ EOB
1125
+ out.push(s)
1126
+ end
1127
+ end
1128
+ Gen.output.join(out)
1129
+ %>
1130
+
1131
+ // Operation response type makers.
1132
+
1133
+ <%=
1134
+ out = []
1135
+ Gen.doc.dig('components', 'responses').each do |name, response|
1136
+ name2type = response[:name2type]
1137
+ next if name2type.nil? # Nothing was made.
1138
+ content = response['content'] || {}
1139
+ response[:pass] = []
1140
+ response[:fail] = []
1141
+ response[:null] = []
1142
+ response[:typefail] = []
1143
+ commons = {}
1144
+ [ :pass, :fail, :null, :typefail ].each do |kind|
1145
+ n2t_keys = name2type.keys.sort!
1146
+ n2t_keys.size.times do |chosen|
1147
+ type_makers = []
1148
+ n2t_keys.size.times do |k|
1149
+ t = name2type[n2t_keys[k]]
1150
+ needed = (k == chosen) ? kind : :pass
1151
+ if needed == :null
1152
+ type_makers.push({ maker: nil, type: t, name: t[:name] })
1153
+ next
1154
+ end
1155
+ m = t[:schema][needed].first
1156
+ break if m.nil?
1157
+ type_makers.push({ maker: m, type: t, name: t[:name] })
1158
+ end
1159
+ next if type_makers.size < name2type.size
1160
+ common = type_makers.map do |tm|
1161
+ if tm[:maker].nil?
1162
+ "#{tm[:name]}: null"
1163
+ else
1164
+ "#{tm[:name]}: #{tm[:maker]}()"
1165
+ end
1166
+ end
1167
+ commons[common.join(';')] = { common: common, kind: kind }
1168
+ end
1169
+ end
1170
+ #commons['empty'] = { common: [], kind: :fail } if commons.empty?
1171
+ (commons.values || []).each do |cc|
1172
+ common = cc[:common]
1173
+ category = cc[:kind]
1174
+ make_name(response, category, response[:name])
1175
+ s = <<EOB
1176
+ export function #{response[category].last}(): #{response[:name]} {
1177
+ return {
1178
+ #{common.join(",\n")}
1179
+ } as unknown as #{response[:name]};
1180
+ }
1181
+ EOB
1182
+ out.push(s)
1183
+ content.each do |media_type, mto|
1184
+ [ :pass, :fail, :typefail ].each { |k| mto[k] = [] unless mto.key?(k) }
1185
+ next unless mto.key?(:name)
1186
+ schema = mto[:decoded]
1187
+ if schema[:name] == 'any'
1188
+ make_name(mto, category, mto[:name])
1189
+ lines = [].concat(common, [ "body: {}" ])
1190
+ s = <<EOB
1191
+ export function #{mto[:pass].last}(): #{mto[:name]} {
1192
+ return {
1193
+ #{lines.join(",\n")}
1194
+ } as unknown as #{mto[:name]};
1195
+ }
1196
+ EOB
1197
+ out.push(s)
1198
+ next
1199
+ end
1200
+ [ :pass, :fail, :typefail ].each do |k|
1201
+ kidx = [ :pass, :fail, :typefail ].index(k)
1202
+ catidx = [ :pass, :fail, :typefail ].index(category) || 0
1203
+ cat = [ :pass, :fail, :typefail ][ [ kidx, catidx ].max ]
1204
+ m = schema[k].first
1205
+ next if m.nil?
1206
+ make_name(mto, cat, mto[:name])
1207
+ lines = [].concat(common, [ "body: #{m}()" ])
1208
+ s = <<EOB
1209
+ export function #{mto[cat].last}(): #{mto[:name]} {
1210
+ return {
1211
+ #{lines.join(",\n")}
1212
+ } as unknown as #{mto[:name]};
1213
+ }
1214
+ EOB
1215
+ out.push(s)
1216
+ end
1217
+ # Add one non-object typefail.
1218
+ make_name(mto, :typefail, mto[:name])
1219
+ s = <<EOB
1220
+ export function #{mto[:typefail].last}(): #{mto[:name]} {
1221
+ return 3 as unknown as #{mto[:name]};
1222
+ }
1223
+ EOB
1224
+ out.push(s)
1225
+ end
1226
+ end
1227
+ # Add one non-object typefail.
1228
+ make_name(response, :typefail, response[:name])
1229
+ s = <<EOB
1230
+ export function #{response[:typefail].last}(): #{response[:name]} {
1231
+ return 2 as unknown as #{response[:name]};
1232
+ }
1233
+ EOB
1234
+ out.push(s)
1235
+ end
1236
+ Gen.output.join(out)
1237
+ %>