@sdk-it/dart 0.20.0 → 0.21.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.
package/dist/index.js CHANGED
@@ -1,30 +1,932 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined")
11
+ return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+
34
+ // node_modules/pluralize/pluralize.js
35
+ var require_pluralize = __commonJS({
36
+ "node_modules/pluralize/pluralize.js"(exports, module) {
37
+ "use strict";
38
+ (function(root, pluralize2) {
39
+ if (typeof __require === "function" && typeof exports === "object" && typeof module === "object") {
40
+ module.exports = pluralize2();
41
+ } else if (typeof define === "function" && define.amd) {
42
+ define(function() {
43
+ return pluralize2();
44
+ });
45
+ } else {
46
+ root.pluralize = pluralize2();
47
+ }
48
+ })(exports, function() {
49
+ var pluralRules = [];
50
+ var singularRules = [];
51
+ var uncountables = {};
52
+ var irregularPlurals = {};
53
+ var irregularSingles = {};
54
+ function sanitizeRule(rule) {
55
+ if (typeof rule === "string") {
56
+ return new RegExp("^" + rule + "$", "i");
57
+ }
58
+ return rule;
59
+ }
60
+ function restoreCase(word, token) {
61
+ if (word === token)
62
+ return token;
63
+ if (word === word.toLowerCase())
64
+ return token.toLowerCase();
65
+ if (word === word.toUpperCase())
66
+ return token.toUpperCase();
67
+ if (word[0] === word[0].toUpperCase()) {
68
+ return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
69
+ }
70
+ return token.toLowerCase();
71
+ }
72
+ function interpolate(str, args) {
73
+ return str.replace(/\$(\d{1,2})/g, function(match, index) {
74
+ return args[index] || "";
75
+ });
76
+ }
77
+ function replace(word, rule) {
78
+ return word.replace(rule[0], function(match, index) {
79
+ var result = interpolate(rule[1], arguments);
80
+ if (match === "") {
81
+ return restoreCase(word[index - 1], result);
82
+ }
83
+ return restoreCase(match, result);
84
+ });
85
+ }
86
+ function sanitizeWord(token, word, rules) {
87
+ if (!token.length || uncountables.hasOwnProperty(token)) {
88
+ return word;
89
+ }
90
+ var len = rules.length;
91
+ while (len--) {
92
+ var rule = rules[len];
93
+ if (rule[0].test(word))
94
+ return replace(word, rule);
95
+ }
96
+ return word;
97
+ }
98
+ function replaceWord(replaceMap, keepMap, rules) {
99
+ return function(word) {
100
+ var token = word.toLowerCase();
101
+ if (keepMap.hasOwnProperty(token)) {
102
+ return restoreCase(word, token);
103
+ }
104
+ if (replaceMap.hasOwnProperty(token)) {
105
+ return restoreCase(word, replaceMap[token]);
106
+ }
107
+ return sanitizeWord(token, word, rules);
108
+ };
109
+ }
110
+ function checkWord(replaceMap, keepMap, rules, bool) {
111
+ return function(word) {
112
+ var token = word.toLowerCase();
113
+ if (keepMap.hasOwnProperty(token))
114
+ return true;
115
+ if (replaceMap.hasOwnProperty(token))
116
+ return false;
117
+ return sanitizeWord(token, token, rules) === token;
118
+ };
119
+ }
120
+ function pluralize2(word, count, inclusive) {
121
+ var pluralized = count === 1 ? pluralize2.singular(word) : pluralize2.plural(word);
122
+ return (inclusive ? count + " " : "") + pluralized;
123
+ }
124
+ pluralize2.plural = replaceWord(
125
+ irregularSingles,
126
+ irregularPlurals,
127
+ pluralRules
128
+ );
129
+ pluralize2.isPlural = checkWord(
130
+ irregularSingles,
131
+ irregularPlurals,
132
+ pluralRules
133
+ );
134
+ pluralize2.singular = replaceWord(
135
+ irregularPlurals,
136
+ irregularSingles,
137
+ singularRules
138
+ );
139
+ pluralize2.isSingular = checkWord(
140
+ irregularPlurals,
141
+ irregularSingles,
142
+ singularRules
143
+ );
144
+ pluralize2.addPluralRule = function(rule, replacement) {
145
+ pluralRules.push([sanitizeRule(rule), replacement]);
146
+ };
147
+ pluralize2.addSingularRule = function(rule, replacement) {
148
+ singularRules.push([sanitizeRule(rule), replacement]);
149
+ };
150
+ pluralize2.addUncountableRule = function(word) {
151
+ if (typeof word === "string") {
152
+ uncountables[word.toLowerCase()] = true;
153
+ return;
154
+ }
155
+ pluralize2.addPluralRule(word, "$0");
156
+ pluralize2.addSingularRule(word, "$0");
157
+ };
158
+ pluralize2.addIrregularRule = function(single, plural) {
159
+ plural = plural.toLowerCase();
160
+ single = single.toLowerCase();
161
+ irregularSingles[single] = plural;
162
+ irregularPlurals[plural] = single;
163
+ };
164
+ [
165
+ // Pronouns.
166
+ ["I", "we"],
167
+ ["me", "us"],
168
+ ["he", "they"],
169
+ ["she", "they"],
170
+ ["them", "them"],
171
+ ["myself", "ourselves"],
172
+ ["yourself", "yourselves"],
173
+ ["itself", "themselves"],
174
+ ["herself", "themselves"],
175
+ ["himself", "themselves"],
176
+ ["themself", "themselves"],
177
+ ["is", "are"],
178
+ ["was", "were"],
179
+ ["has", "have"],
180
+ ["this", "these"],
181
+ ["that", "those"],
182
+ // Words ending in with a consonant and `o`.
183
+ ["echo", "echoes"],
184
+ ["dingo", "dingoes"],
185
+ ["volcano", "volcanoes"],
186
+ ["tornado", "tornadoes"],
187
+ ["torpedo", "torpedoes"],
188
+ // Ends with `us`.
189
+ ["genus", "genera"],
190
+ ["viscus", "viscera"],
191
+ // Ends with `ma`.
192
+ ["stigma", "stigmata"],
193
+ ["stoma", "stomata"],
194
+ ["dogma", "dogmata"],
195
+ ["lemma", "lemmata"],
196
+ ["schema", "schemata"],
197
+ ["anathema", "anathemata"],
198
+ // Other irregular rules.
199
+ ["ox", "oxen"],
200
+ ["axe", "axes"],
201
+ ["die", "dice"],
202
+ ["yes", "yeses"],
203
+ ["foot", "feet"],
204
+ ["eave", "eaves"],
205
+ ["goose", "geese"],
206
+ ["tooth", "teeth"],
207
+ ["quiz", "quizzes"],
208
+ ["human", "humans"],
209
+ ["proof", "proofs"],
210
+ ["carve", "carves"],
211
+ ["valve", "valves"],
212
+ ["looey", "looies"],
213
+ ["thief", "thieves"],
214
+ ["groove", "grooves"],
215
+ ["pickaxe", "pickaxes"],
216
+ ["passerby", "passersby"]
217
+ ].forEach(function(rule) {
218
+ return pluralize2.addIrregularRule(rule[0], rule[1]);
219
+ });
220
+ [
221
+ [/s?$/i, "s"],
222
+ [/[^\u0000-\u007F]$/i, "$0"],
223
+ [/([^aeiou]ese)$/i, "$1"],
224
+ [/(ax|test)is$/i, "$1es"],
225
+ [/(alias|[^aou]us|t[lm]as|gas|ris)$/i, "$1es"],
226
+ [/(e[mn]u)s?$/i, "$1s"],
227
+ [/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i, "$1"],
228
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1i"],
229
+ [/(alumn|alg|vertebr)(?:a|ae)$/i, "$1ae"],
230
+ [/(seraph|cherub)(?:im)?$/i, "$1im"],
231
+ [/(her|at|gr)o$/i, "$1oes"],
232
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i, "$1a"],
233
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, "$1a"],
234
+ [/sis$/i, "ses"],
235
+ [/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i, "$1$2ves"],
236
+ [/([^aeiouy]|qu)y$/i, "$1ies"],
237
+ [/([^ch][ieo][ln])ey$/i, "$1ies"],
238
+ [/(x|ch|ss|sh|zz)$/i, "$1es"],
239
+ [/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, "$1ices"],
240
+ [/\b((?:tit)?m|l)(?:ice|ouse)$/i, "$1ice"],
241
+ [/(pe)(?:rson|ople)$/i, "$1ople"],
242
+ [/(child)(?:ren)?$/i, "$1ren"],
243
+ [/eaux$/i, "$0"],
244
+ [/m[ae]n$/i, "men"],
245
+ ["thou", "you"]
246
+ ].forEach(function(rule) {
247
+ return pluralize2.addPluralRule(rule[0], rule[1]);
248
+ });
249
+ [
250
+ [/s$/i, ""],
251
+ [/(ss)$/i, "$1"],
252
+ [/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i, "$1fe"],
253
+ [/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, "$1f"],
254
+ [/ies$/i, "y"],
255
+ [/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i, "$1ie"],
256
+ [/\b(mon|smil)ies$/i, "$1ey"],
257
+ [/\b((?:tit)?m|l)ice$/i, "$1ouse"],
258
+ [/(seraph|cherub)im$/i, "$1"],
259
+ [/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i, "$1"],
260
+ [/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i, "$1sis"],
261
+ [/(movie|twelve|abuse|e[mn]u)s$/i, "$1"],
262
+ [/(test)(?:is|es)$/i, "$1is"],
263
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1us"],
264
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i, "$1um"],
265
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i, "$1on"],
266
+ [/(alumn|alg|vertebr)ae$/i, "$1a"],
267
+ [/(cod|mur|sil|vert|ind)ices$/i, "$1ex"],
268
+ [/(matr|append)ices$/i, "$1ix"],
269
+ [/(pe)(rson|ople)$/i, "$1rson"],
270
+ [/(child)ren$/i, "$1"],
271
+ [/(eau)x?$/i, "$1"],
272
+ [/men$/i, "man"]
273
+ ].forEach(function(rule) {
274
+ return pluralize2.addSingularRule(rule[0], rule[1]);
275
+ });
276
+ [
277
+ // Singular words with no plurals.
278
+ "adulthood",
279
+ "advice",
280
+ "agenda",
281
+ "aid",
282
+ "aircraft",
283
+ "alcohol",
284
+ "ammo",
285
+ "analytics",
286
+ "anime",
287
+ "athletics",
288
+ "audio",
289
+ "bison",
290
+ "blood",
291
+ "bream",
292
+ "buffalo",
293
+ "butter",
294
+ "carp",
295
+ "cash",
296
+ "chassis",
297
+ "chess",
298
+ "clothing",
299
+ "cod",
300
+ "commerce",
301
+ "cooperation",
302
+ "corps",
303
+ "debris",
304
+ "diabetes",
305
+ "digestion",
306
+ "elk",
307
+ "energy",
308
+ "equipment",
309
+ "excretion",
310
+ "expertise",
311
+ "firmware",
312
+ "flounder",
313
+ "fun",
314
+ "gallows",
315
+ "garbage",
316
+ "graffiti",
317
+ "hardware",
318
+ "headquarters",
319
+ "health",
320
+ "herpes",
321
+ "highjinks",
322
+ "homework",
323
+ "housework",
324
+ "information",
325
+ "jeans",
326
+ "justice",
327
+ "kudos",
328
+ "labour",
329
+ "literature",
330
+ "machinery",
331
+ "mackerel",
332
+ "mail",
333
+ "media",
334
+ "mews",
335
+ "moose",
336
+ "music",
337
+ "mud",
338
+ "manga",
339
+ "news",
340
+ "only",
341
+ "personnel",
342
+ "pike",
343
+ "plankton",
344
+ "pliers",
345
+ "police",
346
+ "pollution",
347
+ "premises",
348
+ "rain",
349
+ "research",
350
+ "rice",
351
+ "salmon",
352
+ "scissors",
353
+ "series",
354
+ "sewage",
355
+ "shambles",
356
+ "shrimp",
357
+ "software",
358
+ "species",
359
+ "staff",
360
+ "swine",
361
+ "tennis",
362
+ "traffic",
363
+ "transportation",
364
+ "trout",
365
+ "tuna",
366
+ "wealth",
367
+ "welfare",
368
+ "whiting",
369
+ "wildebeest",
370
+ "wildlife",
371
+ "you",
372
+ /pok[eé]mon$/i,
373
+ // Regexes.
374
+ /[^aeiou]ese$/i,
375
+ // "chinese", "japanese"
376
+ /deer$/i,
377
+ // "deer", "reindeer"
378
+ /fish$/i,
379
+ // "fish", "blowfish", "angelfish"
380
+ /measles$/i,
381
+ /o[iu]s$/i,
382
+ // "carnivorous"
383
+ /pox$/i,
384
+ // "chickpox", "smallpox"
385
+ /sheep$/i
386
+ ].forEach(pluralize2.addUncountableRule);
387
+ return pluralize2;
388
+ });
389
+ }
390
+ });
391
+
1
392
  // packages/dart/src/lib/generate.ts
2
393
  import { parse as partContentType } from "fast-content-type-parse";
3
394
  import { merge as merge2 } from "lodash-es";
4
395
  import assert2 from "node:assert";
5
- import { writeFile } from "node:fs/promises";
396
+ import { readdir, writeFile } from "node:fs/promises";
6
397
  import { join } from "node:path";
7
398
  import { camelcase as camelcase3 } from "stringcase";
8
399
  import yaml from "yaml";
9
400
  import {
10
401
  followRef as followRef3,
11
- isEmpty as isEmpty2,
12
- isRef as isRef3,
402
+ isEmpty as isEmpty3,
403
+ isRef as isRef4,
13
404
  notRef as notRef2,
14
405
  pascalcase as pascalcase2,
15
406
  snakecase as snakecase2
16
407
  } from "@sdk-it/core";
17
- import { getFolderExportsV2, writeFiles } from "@sdk-it/core/file-system.js";
408
+ import {
409
+ getFolderExportsV2,
410
+ writeFiles
411
+ } from "@sdk-it/core/file-system.js";
18
412
 
19
- // packages/spec/dist/lib/loaders/local-loader.js
20
- import { parse } from "yaml";
413
+ // packages/spec/dist/lib/operation.js
414
+ import { camelcase } from "stringcase";
415
+ import { followRef, isRef as isRef2 } from "@sdk-it/core/ref.js";
21
416
 
22
- // packages/spec/dist/lib/loaders/remote-loader.js
23
- import { parse as parse2 } from "yaml";
417
+ // packages/spec/dist/lib/pagination/pagination.js
418
+ import { isRef } from "@sdk-it/core/ref.js";
419
+ import { isEmpty } from "@sdk-it/core/utils.js";
420
+
421
+ // packages/spec/dist/lib/pagination/pagination-result.js
422
+ var import_pluralize = __toESM(require_pluralize(), 1);
423
+ var PRIMARY_TOP_TIER_KEYWORDS = [
424
+ "data",
425
+ "items",
426
+ "results",
427
+ "value"
428
+ ];
429
+ var PRIMARY_OTHER_KEYWORDS = [
430
+ "records",
431
+ "content",
432
+ "list",
433
+ "payload",
434
+ "entities",
435
+ "collection",
436
+ "users",
437
+ "products",
438
+ "orders",
439
+ "bookings",
440
+ "articles",
441
+ "posts",
442
+ "documents",
443
+ "events"
444
+ ];
445
+ var SECONDARY_KEYWORDS = ["entries", "rows", "elements"];
446
+ var PLURAL_DEPRIORITIZE_LIST = [
447
+ "status",
448
+ "success",
449
+ "address",
450
+ "details",
451
+ "properties",
452
+ "params",
453
+ "headers",
454
+ "cookies",
455
+ "series",
456
+ "links",
457
+ "meta",
458
+ "metadata",
459
+ "statistics",
460
+ "settings",
461
+ "options",
462
+ "permissions",
463
+ "credentials",
464
+ "diagnostics",
465
+ "warnings",
466
+ "errors",
467
+ "actions",
468
+ "attributes",
469
+ "categories",
470
+ "features",
471
+ "includes",
472
+ "tags"
473
+ ];
474
+ var HAS_MORE_PRIMARY_POSITIVE_EXACT = [
475
+ "hasmore",
476
+ "hasnext",
477
+ "hasnextpage",
478
+ "moreitems",
479
+ "moreitemsavailable",
480
+ "nextpage",
481
+ "nextpageexists",
482
+ "nextpageavailable",
483
+ "hasadditionalresults",
484
+ "moreresultsavailable",
485
+ "canloadmore",
486
+ "hasadditional",
487
+ "additionalitems",
488
+ "fetchmore"
489
+ ];
490
+ var HAS_MORE_SECONDARY_POSITIVE_EXACT = ["more", "next"];
491
+ var HAS_MORE_PRIMARY_INVERTED_EXACT = [
492
+ "islast",
493
+ "lastpage",
494
+ "endofresults",
495
+ "endoflist",
496
+ "nomoreitems",
497
+ "nomoredata",
498
+ "allitemsloaded",
499
+ "iscomplete",
500
+ "completed"
501
+ ];
502
+ var HAS_MORE_POSITIVE_REGEX_PATTERNS = [
503
+ "\\bhas_?more\\b",
504
+ "\\bhas_?next\\b",
505
+ // e.g., itemsHasNext, items_has_next
506
+ "\\bmore_?items\\b",
507
+ "\\bnext_?page\\b",
508
+ // e.g., userNextPageFlag
509
+ "\\badditional\\b",
510
+ // e.g., hasAdditionalData, additional_results_exist
511
+ "\\bcontinuation\\b",
512
+ // e.g., continuationAvailable, has_continuation_token
513
+ "\\bmore_?results\\b",
514
+ "\\bpage_?available\\b",
515
+ "\\bnext(?:_?(page))?\\b"
516
+ ];
517
+ var COMPILED_HAS_MORE_POSITIVE_REGEXES = HAS_MORE_POSITIVE_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
518
+ var HAS_MORE_INVERTED_REGEX_PATTERNS = [
519
+ "\\bis_?last\\b",
520
+ // e.g., pageIsLast
521
+ "\\blast_?page\\b",
522
+ // e.g., resultsAreLastPage
523
+ "\\bend_?of_?(data|results|list|items|stream)\\b",
524
+ "\\bno_?more_?(items|data|results)?\\b",
525
+ "\\ball_?(items_?)?loaded\\b",
526
+ "\\bis_?complete\\b"
527
+ ];
528
+ var COMPILED_HAS_MORE_INVERTED_REGEXES = HAS_MORE_INVERTED_REGEX_PATTERNS.map((p) => new RegExp(p, "i"));
529
+ function getItemsName(properties) {
530
+ const arrayPropertyNames = [];
531
+ for (const propName in properties) {
532
+ if (propName in properties) {
533
+ const propSchema = properties[propName];
534
+ if (propSchema && propSchema.type === "array") {
535
+ arrayPropertyNames.push(propName);
536
+ }
537
+ }
538
+ }
539
+ if (arrayPropertyNames.length === 0) {
540
+ return null;
541
+ }
542
+ if (arrayPropertyNames.length === 1) {
543
+ return arrayPropertyNames[0];
544
+ }
545
+ let bestCandidate = null;
546
+ let candidateRank = Infinity;
547
+ const updateCandidate = (propName, rank) => {
548
+ if (rank < candidateRank) {
549
+ bestCandidate = propName;
550
+ candidateRank = rank;
551
+ }
552
+ };
553
+ for (const propName of arrayPropertyNames) {
554
+ const lowerPropName = propName.toLowerCase();
555
+ if (PRIMARY_TOP_TIER_KEYWORDS.includes(lowerPropName)) {
556
+ updateCandidate(propName, 2);
557
+ continue;
558
+ }
559
+ if (candidateRank > 3 && PRIMARY_OTHER_KEYWORDS.includes(lowerPropName)) {
560
+ updateCandidate(propName, 3);
561
+ continue;
562
+ }
563
+ if (candidateRank > 4 && SECONDARY_KEYWORDS.includes(lowerPropName)) {
564
+ updateCandidate(propName, 4);
565
+ continue;
566
+ }
567
+ if (candidateRank > 5 && import_pluralize.default.isPlural(propName) && !PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
568
+ updateCandidate(propName, 5);
569
+ continue;
570
+ }
571
+ if (candidateRank > 6 && import_pluralize.default.isPlural(propName) && PLURAL_DEPRIORITIZE_LIST.includes(lowerPropName)) {
572
+ updateCandidate(propName, 6);
573
+ continue;
574
+ }
575
+ }
576
+ if (bestCandidate) {
577
+ return bestCandidate;
578
+ }
579
+ return arrayPropertyNames[0];
580
+ }
581
+ function guess(properties) {
582
+ const booleanPropertyNames = [];
583
+ for (const propName in properties) {
584
+ if (Object.prototype.hasOwnProperty.call(properties, propName)) {
585
+ const propSchema = properties[propName];
586
+ if (propSchema && propSchema.type === "boolean" || propSchema.type === "integer") {
587
+ booleanPropertyNames.push(propName);
588
+ }
589
+ }
590
+ }
591
+ if (booleanPropertyNames.length === 0) {
592
+ return null;
593
+ }
594
+ if (booleanPropertyNames.length === 1) {
595
+ return booleanPropertyNames[0];
596
+ }
597
+ let bestCandidate = null;
598
+ let candidateRank = Infinity;
599
+ const updateCandidate = (propName, rank) => {
600
+ if (rank < candidateRank) {
601
+ bestCandidate = propName;
602
+ candidateRank = rank;
603
+ }
604
+ };
605
+ for (const propName of booleanPropertyNames) {
606
+ const normalizedForExactMatch = propName.toLowerCase().replace(/[-_]/g, "");
607
+ let currentPropRank = Infinity;
608
+ if (HAS_MORE_PRIMARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
609
+ currentPropRank = 1;
610
+ } else if (HAS_MORE_SECONDARY_POSITIVE_EXACT.includes(normalizedForExactMatch)) {
611
+ currentPropRank = 2;
612
+ } else {
613
+ let foundPositiveRegex = false;
614
+ for (const regex of COMPILED_HAS_MORE_POSITIVE_REGEXES) {
615
+ if (regex.test(propName)) {
616
+ currentPropRank = 3;
617
+ foundPositiveRegex = true;
618
+ break;
619
+ }
620
+ }
621
+ if (!foundPositiveRegex) {
622
+ if (HAS_MORE_PRIMARY_INVERTED_EXACT.includes(normalizedForExactMatch)) {
623
+ currentPropRank = 4;
624
+ } else {
625
+ for (const regex of COMPILED_HAS_MORE_INVERTED_REGEXES) {
626
+ if (regex.test(propName)) {
627
+ currentPropRank = 5;
628
+ break;
629
+ }
630
+ }
631
+ }
632
+ }
633
+ }
634
+ updateCandidate(propName, currentPropRank);
635
+ }
636
+ return bestCandidate;
637
+ }
638
+ function getHasMoreName(properties) {
639
+ const rootGuess = guess(properties);
640
+ if (rootGuess) {
641
+ return rootGuess;
642
+ }
643
+ for (const propName in properties) {
644
+ const propSchema = properties[propName];
645
+ if (propSchema.type === "object" && propSchema.properties) {
646
+ const nested = getHasMoreName(propSchema.properties);
647
+ if (nested) {
648
+ return propName + "." + nested;
649
+ }
650
+ }
651
+ }
652
+ return null;
653
+ }
654
+
655
+ // packages/spec/dist/lib/pagination/pagination.js
656
+ var OFFSET_PARAM_REGEXES = [
657
+ /\boffset\b/i,
658
+ /\bskip\b/i,
659
+ /\bstart(?:ing_at|_index)?\b/i,
660
+ // e.g., start, starting_at, start_index
661
+ /\bfrom\b/i
662
+ ];
663
+ var GENERIC_LIMIT_PARAM_REGEXES = [
664
+ /\blimit\b/i,
665
+ /\bcount\b/i,
666
+ /\b(?:page_?)?size\b/i,
667
+ // e.g., size, page_size, pagesize
668
+ /\bmax_results\b/i,
669
+ /\bnum_results\b/i,
670
+ /\bshow\b/i,
671
+ // Can sometimes mean limit
672
+ /\bper_?page\b/i,
673
+ // e.g., per_page, perpage
674
+ /\bper-page\b/i,
675
+ /\btake\b/i
676
+ ];
677
+ var PAGE_NUMBER_REGEXES = [
678
+ /^page$/i,
679
+ // Exact match for "page"
680
+ /^p$/i,
681
+ // Exact match for "p" (common shorthand)
682
+ /\bpage_?(?:number|num|idx|index)\b/i
683
+ // e.g., page_number, pageNumber, page_num, page_idx
684
+ ];
685
+ var PAGE_SIZE_REGEXES = [
686
+ /\bpage_?size\b/i,
687
+ // e.g., page_size, pagesize
688
+ /^size$/i,
689
+ // Exact "size"
690
+ // /\bsize\b/i, // Broader "size" - can be ambiguous, prefer more specific ones first
691
+ /\blimit\b/i,
692
+ // Limit is often used for page size
693
+ /\bcount\b/i,
694
+ // Count can also be used for page size
695
+ /\bper_?page\b/i,
696
+ // e.g., per_page, perpage
697
+ /\bper-page\b/i,
698
+ /\bnum_?(?:items|records|results)\b/i,
699
+ // e.g., num_items, numitems
700
+ /\bresults_?per_?page\b/i
701
+ ];
702
+ var CURSOR_REGEXES = [
703
+ /\bcursor\b/i,
704
+ /\bafter(?:_?cursor)?\b/i,
705
+ // e.g., after, after_cursor
706
+ /\bbefore(?:_?cursor)?\b/i,
707
+ // e.g., before, before_cursor
708
+ /\b(next|prev|previous)_?(?:page_?)?token\b/i,
709
+ // e.g., next_page_token, nextPageToken, prev_token
710
+ /\b(next|prev|previous)_?cursor\b/i,
711
+ // e.g., next_cursor, previousCursor
712
+ /\bcontinuation(?:_?token)?\b/i,
713
+ // e.g., continuation, continuation_token
714
+ /\bpage(?:_?(token|id))?\b/i,
715
+ // e.g., after, after_cursor
716
+ /\bstart_?(?:key|cursor|token|after)\b/i
717
+ // e.g., start_key, startCursor, startToken, startAfter
718
+ ];
719
+ var CURSOR_LIMIT_REGEXES = [
720
+ /\blimit\b/i,
721
+ /\bcount\b/i,
722
+ /\bsize\b/i,
723
+ // General size
724
+ /\bfirst\b/i,
725
+ // Common in Relay-style cursor pagination (forward pagination)
726
+ /\blast\b/i,
727
+ // Common in Relay-style cursor pagination (backward pagination)
728
+ /\bpage_?size\b/i,
729
+ // Sometimes page_size is used with cursors
730
+ /\bnum_?(?:items|records|results)\b/i,
731
+ // e.g., num_items
732
+ /\bmax_?items\b/i,
733
+ /\btake\b/i
734
+ ];
735
+ function findParamAndKeyword(queryParams, regexes, excludeParamName) {
736
+ for (const param of queryParams) {
737
+ if (param.name === excludeParamName) {
738
+ continue;
739
+ }
740
+ for (const regex of regexes) {
741
+ const match = param.name.match(regex);
742
+ if (match) {
743
+ return { param, keyword: match[0] };
744
+ }
745
+ }
746
+ }
747
+ return null;
748
+ }
749
+ function isOffsetPagination(operation, parameters) {
750
+ const offsetMatch = findParamAndKeyword(parameters, OFFSET_PARAM_REGEXES);
751
+ if (!offsetMatch)
752
+ return null;
753
+ const limitMatch = findParamAndKeyword(
754
+ parameters,
755
+ GENERIC_LIMIT_PARAM_REGEXES,
756
+ offsetMatch.param.name
757
+ );
758
+ if (!limitMatch)
759
+ return null;
760
+ return {
761
+ type: "offset",
762
+ offsetParamName: offsetMatch.param.name,
763
+ offsetKeyword: offsetMatch.keyword,
764
+ limitParamName: limitMatch.param.name,
765
+ limitKeyword: limitMatch.keyword
766
+ };
767
+ }
768
+ function isPagePagination(operation) {
769
+ const queryParams = operation.parameters.filter((p) => p.in === "query").filter(
770
+ (it) => it.schema && !isRef(it.schema) && it.schema.type === "integer"
771
+ );
772
+ if (queryParams.length < 2)
773
+ return null;
774
+ const pageNoMatch = findParamAndKeyword(queryParams, PAGE_NUMBER_REGEXES);
775
+ if (!pageNoMatch)
776
+ return null;
777
+ const pageSizeMatch = findParamAndKeyword(
778
+ queryParams,
779
+ PAGE_SIZE_REGEXES,
780
+ pageNoMatch.param.name
781
+ );
782
+ if (!pageSizeMatch)
783
+ return null;
784
+ return {
785
+ type: "page",
786
+ pageNumberParamName: pageNoMatch.param.name,
787
+ pageNumberKeyword: pageNoMatch.keyword,
788
+ pageSizeParamName: pageSizeMatch.param.name,
789
+ pageSizeKeyword: pageSizeMatch.keyword
790
+ };
791
+ }
792
+ function isCursorPagination(operation) {
793
+ const queryParams = operation.parameters.filter((p) => p.in === "query");
794
+ if (queryParams.length < 2)
795
+ return null;
796
+ const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);
797
+ if (!cursorMatch)
798
+ return null;
799
+ const limitMatch = findParamAndKeyword(
800
+ queryParams,
801
+ CURSOR_LIMIT_REGEXES,
802
+ cursorMatch.param.name
803
+ );
804
+ if (!limitMatch)
805
+ return null;
806
+ return {
807
+ type: "cursor",
808
+ cursorParamName: cursorMatch.param.name,
809
+ cursorKeyword: cursorMatch.keyword,
810
+ limitParamName: limitMatch.param.name,
811
+ limitKeyword: limitMatch.keyword
812
+ };
813
+ }
814
+ function guessPagination(operation, body, response) {
815
+ const bodyParameters = body && body.properties ? Object.keys(body.properties).map((it) => ({ name: it })) : [];
816
+ const parameters = operation.parameters;
817
+ if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {
818
+ return { type: "none", reason: "no parameters" };
819
+ }
820
+ if (!response) {
821
+ return { type: "none", reason: "no response" };
822
+ }
823
+ if (!response.properties) {
824
+ return { type: "none", reason: "empty response" };
825
+ }
826
+ const properties = response.properties;
827
+ const itemsKey = getItemsName(properties);
828
+ if (!itemsKey) {
829
+ return { type: "none", reason: "no items key" };
830
+ }
831
+ const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));
832
+ if (!hasMoreKey) {
833
+ return { type: "none", reason: "no hasMore key" };
834
+ }
835
+ const pagination = isOffsetPagination(operation, [...parameters, ...bodyParameters]) || isPagePagination(operation) || isCursorPagination(operation);
836
+ return pagination ? { ...pagination, items: itemsKey, hasMore: hasMoreKey } : { type: "none", reason: "no pagination" };
837
+ }
838
+ function excludeKey(obj, key) {
839
+ const { [key]: _, ...rest } = obj;
840
+ return rest;
841
+ }
24
842
 
25
843
  // packages/spec/dist/lib/operation.js
26
- import { camelcase } from "stringcase";
27
- import { followRef, isRef } from "@sdk-it/core";
844
+ function augmentSpec(config) {
845
+ config.spec.paths ??= {};
846
+ const paths = {};
847
+ for (const [path, pathItem] of Object.entries(config.spec.paths)) {
848
+ const { parameters = [], ...methods } = pathItem;
849
+ const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
850
+ for (const [method, operation] of Object.entries(methods)) {
851
+ const formatOperationId = config.operationId ?? defaults.operationId;
852
+ const formatTag = config.tag ?? defaults.tag;
853
+ const operationId = formatOperationId(operation, fixedPath, method);
854
+ const operationTag = formatTag(operation, fixedPath);
855
+ const requestBody = isRef2(operation.requestBody) ? followRef(config.spec, operation.requestBody.$ref) : operation.requestBody;
856
+ const tunedOperation = {
857
+ ...operation,
858
+ parameters: [...parameters, ...operation.parameters ?? []].map(
859
+ (it) => isRef2(it) ? followRef(config.spec, it.$ref) : it
860
+ ),
861
+ tags: [operationTag],
862
+ operationId,
863
+ responses: resolveResponses(config.spec, operation),
864
+ requestBody
865
+ };
866
+ tunedOperation["x-pagination"] = toPagination(
867
+ config.spec,
868
+ tunedOperation
869
+ );
870
+ Object.assign(paths, {
871
+ [fixedPath]: {
872
+ ...paths[fixedPath],
873
+ [method]: tunedOperation
874
+ }
875
+ });
876
+ }
877
+ }
878
+ return { ...config.spec, paths };
879
+ }
880
+ function toPagination(spec, tunedOperation) {
881
+ if (tunedOperation["x-pagination"]) {
882
+ return tunedOperation["x-pagination"];
883
+ }
884
+ const schema = getResponseContentSchema(
885
+ spec,
886
+ tunedOperation.responses["200"],
887
+ "application/json"
888
+ );
889
+ const pagination = guessPagination(
890
+ tunedOperation,
891
+ tunedOperation.requestBody ? getRequestContentSchema(
892
+ spec,
893
+ tunedOperation.requestBody,
894
+ "application/json"
895
+ ) : void 0,
896
+ schema
897
+ );
898
+ if (pagination && pagination.type !== "none" && schema) {
899
+ return pagination;
900
+ }
901
+ return void 0;
902
+ }
903
+ function getResponseContentSchema(spec, response, type) {
904
+ if (!response) {
905
+ return void 0;
906
+ }
907
+ const content = response.content;
908
+ if (!content) {
909
+ return void 0;
910
+ }
911
+ for (const contentType in content) {
912
+ if (contentType.toLowerCase() === type.toLowerCase()) {
913
+ return isRef2(content[contentType].schema) ? followRef(spec, content[contentType].schema.$ref) : content[contentType].schema;
914
+ }
915
+ }
916
+ return void 0;
917
+ }
918
+ function getRequestContentSchema(spec, requestBody, type) {
919
+ const content = requestBody.content;
920
+ if (!content) {
921
+ return void 0;
922
+ }
923
+ for (const contentType in content) {
924
+ if (contentType.toLowerCase() === type.toLowerCase()) {
925
+ return isRef2(content[contentType].schema) ? followRef(spec, content[contentType].schema.$ref) : content[contentType].schema;
926
+ }
927
+ }
928
+ return void 0;
929
+ }
28
930
  var defaults = {
29
931
  operationId: (operation, path, method) => {
30
932
  if (operation.operationId) {
@@ -46,7 +948,7 @@ function resolveResponses(spec, operation) {
46
948
  const responses = operation.responses ?? {};
47
949
  const resolved = {};
48
950
  for (const status in responses) {
49
- const response = isRef(responses[status]) ? followRef(spec, responses[status].$ref) : responses[status];
951
+ const response = isRef2(responses[status]) ? followRef(spec, responses[status].$ref) : responses[status];
50
952
  resolved[status] = response;
51
953
  }
52
954
  return resolved;
@@ -55,28 +957,19 @@ function forEachOperation(config, callback) {
55
957
  const result = [];
56
958
  for (const [path, pathItem] of Object.entries(config.spec.paths ?? {})) {
57
959
  const { parameters = [], ...methods } = pathItem;
58
- const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
59
960
  for (const [method, operation] of Object.entries(methods)) {
60
- const formatOperationId = config.operationId ?? defaults.operationId;
61
- const formatTag = config.tag ?? defaults.tag;
62
- const operationName = formatOperationId(operation, fixedPath, method);
63
- const operationTag = formatTag(operation, fixedPath);
64
961
  const metadata = operation["x-oaiMeta"] ?? {};
962
+ const operationTag = operation.tags?.[0];
65
963
  result.push(
66
964
  callback(
67
965
  {
68
966
  name: metadata.name,
69
967
  method,
70
- path: fixedPath,
968
+ path,
71
969
  groupName: operationTag,
72
970
  tag: operationTag
73
971
  },
74
- {
75
- ...operation,
76
- parameters: [...parameters, ...operation.parameters ?? []],
77
- operationId: operationName,
78
- responses: resolveResponses(config.spec, operation)
79
- }
972
+ operation
80
973
  )
81
974
  );
82
975
  }
@@ -287,6 +1180,68 @@ function isSuccessStatusCode(statusCode) {
287
1180
  statusCode = Number(statusCode);
288
1181
  return statusCode >= 200 && statusCode < 300;
289
1182
  }
1183
+ function patchParameters(spec, objectSchema, operation) {
1184
+ const securitySchemes = spec.components?.securitySchemes ?? {};
1185
+ const securityOptions = securityToOptions(
1186
+ spec,
1187
+ operation.security ?? [],
1188
+ securitySchemes
1189
+ );
1190
+ objectSchema.properties ??= {};
1191
+ objectSchema.required ??= [];
1192
+ for (const param of operation.parameters) {
1193
+ if (param.required) {
1194
+ objectSchema.required.push(param.name);
1195
+ }
1196
+ objectSchema.properties[param.name] = isRef2(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" };
1197
+ }
1198
+ for (const param of securityOptions) {
1199
+ objectSchema.required = (objectSchema.required ?? []).filter(
1200
+ (name) => name !== param.name
1201
+ );
1202
+ objectSchema.properties[param.name] = isRef2(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" };
1203
+ }
1204
+ }
1205
+ function securityToOptions(spec, security, securitySchemes, staticIn) {
1206
+ securitySchemes ??= {};
1207
+ const parameters = [];
1208
+ for (const it of security) {
1209
+ const [name] = Object.keys(it);
1210
+ if (!name) {
1211
+ continue;
1212
+ }
1213
+ const schema = isRef2(securitySchemes[name]) ? followRef(spec, securitySchemes[name].$ref) : securitySchemes[name];
1214
+ if (schema.type === "http") {
1215
+ parameters.push({
1216
+ in: staticIn ?? "header",
1217
+ name: "authorization",
1218
+ schema: { type: "string" }
1219
+ });
1220
+ continue;
1221
+ }
1222
+ if (schema.type === "apiKey") {
1223
+ if (!schema.in) {
1224
+ throw new Error(`apiKey security schema must have an "in" field`);
1225
+ }
1226
+ if (!schema.name) {
1227
+ throw new Error(`apiKey security schema must have a "name" field`);
1228
+ }
1229
+ parameters.push({
1230
+ in: staticIn ?? schema.in,
1231
+ name: schema.name,
1232
+ schema: { type: "string" }
1233
+ });
1234
+ continue;
1235
+ }
1236
+ }
1237
+ return parameters;
1238
+ }
1239
+
1240
+ // packages/spec/dist/lib/loaders/local-loader.js
1241
+ import { parse } from "yaml";
1242
+
1243
+ // packages/spec/dist/lib/loaders/remote-loader.js
1244
+ import { parse as parse2 } from "yaml";
290
1245
 
291
1246
  // packages/dart/src/lib/dart-emitter.ts
292
1247
  import { merge } from "lodash-es";
@@ -295,8 +1250,8 @@ import { camelcase as camelcase2, snakecase } from "stringcase";
295
1250
  import {
296
1251
  cleanRef,
297
1252
  followRef as followRef2,
298
- isEmpty,
299
- isRef as isRef2,
1253
+ isEmpty as isEmpty2,
1254
+ isRef as isRef3,
300
1255
  notRef,
301
1256
  parseRef,
302
1257
  pascalcase
@@ -344,7 +1299,7 @@ var DartSerializer = class {
344
1299
  this.#spec.components.schemas ??= {};
345
1300
  this.#spec.components.responses ??= {};
346
1301
  const checkSchema = (schema) => {
347
- if (isRef2(schema)) {
1302
+ if (isRef3(schema)) {
348
1303
  const { model } = parseRef(schema.$ref);
349
1304
  return model === schemaName;
350
1305
  }
@@ -377,7 +1332,7 @@ var DartSerializer = class {
377
1332
  matches: `json['${camelcase2(context.name)}'] is Map<String, dynamic>`
378
1333
  };
379
1334
  }
380
- if (isEmpty(schema.properties)) {
1335
+ if (isEmpty2(schema.properties)) {
381
1336
  if (context.noEmit !== true) {
382
1337
  this.#emit(
383
1338
  className,
@@ -563,7 +1518,7 @@ return ${matches.join(" && ")};
563
1518
  // fixme: this method should no longer be needed because the logic in it is being preprocessed before emitting begins
564
1519
  #allOf(className, schemas, context) {
565
1520
  const name = pascalcase(context.propName || className);
566
- const refs = schemas.filter(isRef2);
1521
+ const refs = schemas.filter(isRef3);
567
1522
  const nonRefs = schemas.filter(notRef);
568
1523
  if (nonRefs.some((it) => it.type && it.type !== "object")) {
569
1524
  assert(false, `allOf ${name} must be an object`);
@@ -587,7 +1542,7 @@ return ${matches.join(" && ")};
587
1542
  };
588
1543
  }
589
1544
  const nullSchemaIndex = schemas.findIndex((schema) => {
590
- if (isRef2(schema)) {
1545
+ if (isRef3(schema)) {
591
1546
  const refSchema = followRef2(this.#spec, schema.$ref);
592
1547
  return refSchema.type === "null";
593
1548
  }
@@ -628,7 +1583,7 @@ return ${matches.join(" && ")};
628
1583
  const patterns = [];
629
1584
  const objects = schemas.filter(notRef).filter((it) => it.type === "object");
630
1585
  for (const schema of schemas) {
631
- if (isRef2(schema)) {
1586
+ if (isRef3(schema)) {
632
1587
  const refType = this.#ref(className, schema.$ref, true, context);
633
1588
  patterns.push({
634
1589
  pattern: `case ${refType.type || "Map<String, dynamic>"} map when ${refType.use}.matches(map): return ${refType.use}.fromJson(map);`,
@@ -879,7 +1834,7 @@ return false;
879
1834
  };
880
1835
  }
881
1836
  #serialize(className, schema, required = true, context = {}) {
882
- if (isRef2(schema)) {
1837
+ if (isRef3(schema)) {
883
1838
  return this.#ref(className, schema.$ref, required, context);
884
1839
  }
885
1840
  if (schema.allOf && Array.isArray(schema.allOf)) {
@@ -943,14 +1898,14 @@ return false;
943
1898
  }
944
1899
  };
945
1900
  function isObjectSchema(schema) {
946
- return !isRef2(schema) && (schema.type === "object" || !!schema.properties);
1901
+ return !isRef3(schema) && (schema.type === "object" || !!schema.properties);
947
1902
  }
948
1903
 
949
1904
  // packages/dart/src/lib/http/dispatcher.txt
950
1905
  var dispatcher_default = "import 'dart:convert';\nimport 'dart:io';\n\nimport 'package:http/http.dart' as http;\nimport 'package:http_parser/http_parser.dart';\nimport 'package:mime/mime.dart' as mime;\n\nimport './interceptors.dart';\nimport './responses.dart';\n\nclass Dispatcher {\n final List<Interceptor> interceptors;\n\n Dispatcher(this.interceptors);\n\n Future<http.StreamedResponse> multipart(\n RequestConfig config,\n Map<String, dynamic> body,\n ) async {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.MultipartRequest(\n modifiedConfig.method,\n modifiedConfig.url,\n );\n request.headers.addAll(modifiedConfig.headers);\n for (var entry in body.entries) {\n final key = entry.key;\n final value = entry.value;\n if (value is File) {\n final mimeType = mime.lookupMimeType(value.path);\n request.files.add(\n http.MultipartFile(\n key,\n value.openRead(),\n await value.length(),\n filename: value.uri.pathSegments.last,\n contentType: mimeType != null ? MediaType.parse(mimeType) : null,\n ),\n );\n } else {\n request.fields[key] = value.toString();\n }\n }\n\n return request.send();\n }\n\n Future<http.StreamedResponse> empty(RequestConfig config) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n return request.send();\n }\n\n Future<http.StreamedResponse> json(RequestConfig config, dynamic body) {\n final modifiedConfig = interceptors.fold(\n config,\n (acc, interceptor) => interceptor.before(acc),\n );\n final request = http.Request(modifiedConfig.method, modifiedConfig.url);\n request.headers.addAll(modifiedConfig.headers);\n\n request.headers['Content-Type'] = 'application/json';\n if ((body is Map || body is List)) {\n request.body = jsonEncode(body);\n } else if (body is String) {\n request.body = body;\n } else {\n throw ArgumentError('Unsupported body type: ${body.runtimeType}');\n }\n\n return request.send();\n }\n}\n\nclass Receiver {\n final List<Interceptor> interceptors;\n Receiver(this.interceptors);\n\n dynamic _parse(http.Response response) {\n final contentTypeHeader = response.headers['content-type'];\n final parsed = parseContentType(contentTypeHeader);\n if (parsed.type == 'application/json') {\n return jsonDecode(response.body);\n } else if (parsed.type == 'text/plain') {\n return response.body;\n } else if (parsed.type == 'application/octet-stream') {\n return response.bodyBytes;\n } else {\n throw UnsupportedError('Unsupported content type: ${parsed.type}');\n }\n }\n\n dynamic json(http.StreamedResponse stream) async {\n if (stream.statusCode >= 200 && stream.statusCode < 300) {\n final response = await http.Response.fromStream(stream);\n return _parse(response);\n }\n switch (stream.statusCode) {\n case 400:\n throw BadRequestError('');\n case 401:\n throw UnauthorizedError('');\n case 403:\n throw ForbiddenError('');\n case 404:\n throw NotFoundError('');\n case 500:\n throw InternalServerError('');\n case 402:\n throw PaymentRequiredError('');\n case 405:\n throw MethodNotAllowedError('');\n case 406:\n throw NotAcceptableError('');\n case 409:\n throw ConflictError('');\n case 410:\n throw GoneError('');\n case 422:\n throw UnprocessableEntityError('');\n case 429:\n throw TooManyRequestsError('');\n case 413:\n throw PayloadTooLargeError('');\n case 415:\n throw UnsupportedMediaTypeError('');\n case 501:\n throw NotImplementedError('');\n case 502:\n throw BadGatewayError('');\n case 503:\n throw ServiceUnavailableError('');\n case 504:\n throw GatewayTimeoutError('');\n default:\n throw UnknownApiError('', stream.statusCode);\n }\n }\n}\n\n({String type, Map<String, String> parameters}) parseContentType(\n String? contentTypeHeader,\n) {\n if (contentTypeHeader == null || contentTypeHeader.isEmpty) {\n return (type: '', parameters: {});\n }\n final parts = contentTypeHeader.split(';');\n final type = parts[0].trim();\n final parameters = <String, String>{};\n for (var i = 1; i < parts.length; i++) {\n final param = parts[i].split('=');\n if (param.length == 2) {\n parameters[param[0].trim()] = param[1].trim();\n }\n }\n\n return (type: type, parameters: parameters);\n}\n";
951
1906
 
952
1907
  // packages/dart/src/lib/http/interceptors.txt
953
- var interceptors_default = "abstract class Interceptor {\n RequestConfig before(RequestConfig config);\n void after();\n}\n\nclass BaseUrlInterceptor extends Interceptor {\n final String Function() getBaseUrl;\n BaseUrlInterceptor(this.getBaseUrl);\n\n @override\n RequestConfig before(RequestConfig config) {\n final baseUrl = getBaseUrl();\n if (config.url.scheme.isEmpty) {\n config.url = Uri.parse(baseUrl + config.url.toString());\n }\n return config;\n }\n\n @override\n void after() {\n //\n }\n}\n\nclass RequestConfig {\n final String method;\n Uri url;\n final Map<String, String> headers;\n RequestConfig({required this.method, required this.url, required this.headers});\n}\n";
1908
+ var interceptors_default = "abstract class Interceptor {\n RequestConfig before(RequestConfig config);\n void after();\n}\n\nclass BaseUrlInterceptor extends Interceptor {\n final String Function() getBaseUrl;\n BaseUrlInterceptor(this.getBaseUrl);\n\n @override\n RequestConfig before(RequestConfig config) {\n final baseUrl = getBaseUrl();\n if (config.url.scheme.isEmpty) {\n config.url = Uri.parse(baseUrl + config.url.toString());\n }\n return config;\n }\n\n @override\n void after() {\n //\n }\n}\n\n\nclass LoggingInterceptor extends Interceptor {\n // ANSI color codes\n static const String _reset = '\\x1B[0m';\n static const String _green = '\\x1B[32m';\n static const String _yellow = '\\x1B[33m';\n static const String _blue = '\\x1B[34m';\n static const String _magenta = '\\x1B[35m';\n static const String _cyan = '\\x1B[36m';\n\n @override\n RequestConfig before(RequestConfig config) {\n print('${_cyan}[LOG] --- HTTP REQUEST ---$_reset');\n print('${_yellow}[LOG] Method: ${config.method.toUpperCase()}$_reset');\n print('${_green}[LOG] URL: ${config.url}$_reset');\n print('${_magenta}[ContentType] ${config.headers['content-type']}$_reset');\n if (config.headers.isNotEmpty) {\n print('${_blue}[LOG] Headers: ${config.headers}$_reset');\n } else {\n print('${_blue}[LOG] Headers: <none>$_reset');\n }\n print('${_cyan}[LOG] --------------$_reset');\n return config;\n }\n\n @override\n void after() {\n // Optionally log after the request\n }\n}\n\nclass RequestConfig {\n final String method;\n Uri url;\n final Map<String, String> headers;\n RequestConfig({required this.method, required this.url, required this.headers});\n}\n";
954
1909
 
955
1910
  // packages/dart/src/lib/http/responses.txt
956
1911
  var responses_default = "sealed class ApiError {\n final String message;\n final int? statusCode;\n final String status;\n const ApiError(this.message, {this.statusCode, this.status = ''});\n\n @override\n String toString() =>\n 'ApiError(status: $status, statusCode: $statusCode, message: $message)';\n}\n\nbase class BadRequestError extends ApiError {\n const BadRequestError(String message)\n : super(message, statusCode: 400, status: 'BadRequest');\n}\n\nbase class UnauthorizedError extends ApiError {\n const UnauthorizedError(String message)\n : super(message, statusCode: 401, status: 'Unauthorized');\n}\n\nbase class ForbiddenError extends ApiError {\n const ForbiddenError(String message)\n : super(message, statusCode: 403, status: 'Forbidden');\n}\n\nbase class NotFoundError extends ApiError {\n const NotFoundError(String message)\n : super(message, statusCode: 404, status: 'NotFound');\n}\n\nbase class InternalServerError extends ApiError {\n const InternalServerError(String message)\n : super(message, statusCode: 500, status: 'InternalServerError');\n}\n\nbase class UnknownApiError extends ApiError {\n const UnknownApiError(String message, int statusCode)\n : super(message, statusCode: statusCode, status: 'UnknownApiError');\n}\n\nbase class PaymentRequiredError extends ApiError {\n const PaymentRequiredError(String message)\n : super(message, statusCode: 402, status: 'PaymentRequired');\n}\n\nbase class MethodNotAllowedError extends ApiError {\n const MethodNotAllowedError(String message)\n : super(message, statusCode: 405, status: 'MethodNotAllowed');\n}\n\nbase class NotAcceptableError extends ApiError {\n const NotAcceptableError(String message)\n : super(message, statusCode: 406, status: 'NotAcceptable');\n}\n\nbase class ConflictError extends ApiError {\n const ConflictError(String message)\n : super(message, statusCode: 409, status: 'Conflict');\n}\n\nbase class GoneError extends ApiError {\n const GoneError(String message)\n : super(message, statusCode: 410, status: 'Gone');\n}\n\nbase class UnprocessableEntityError extends ApiError {\n const UnprocessableEntityError(String message)\n : super(message, statusCode: 422, status: 'UnprocessableEntity');\n}\n\nbase class TooManyRequestsError extends ApiError {\n const TooManyRequestsError(String message)\n : super(message, statusCode: 429, status: 'TooManyRequests');\n}\n\nbase class PayloadTooLargeError extends ApiError {\n const PayloadTooLargeError(String message)\n : super(message, statusCode: 413, status: 'PayloadTooLarge');\n}\n\nbase class UnsupportedMediaTypeError extends ApiError {\n const UnsupportedMediaTypeError(String message)\n : super(message, statusCode: 415, status: 'UnsupportedMediaType');\n}\n\nbase class NotImplementedError extends ApiError {\n const NotImplementedError(String message)\n : super(message, statusCode: 501, status: 'NotImplemented');\n}\n\nbase class BadGatewayError extends ApiError {\n const BadGatewayError(String message)\n : super(message, statusCode: 502, status: 'BadGateway');\n}\n\nbase class ServiceUnavailableError extends ApiError {\n const ServiceUnavailableError(String message)\n : super(message, statusCode: 503, status: 'ServiceUnavailable');\n}\n\nbase class GatewayTimeoutError extends ApiError {\n const GatewayTimeoutError(String message)\n : super(message, statusCode: 504, status: 'GatewayTimeout');\n}\n";
@@ -958,14 +1913,14 @@ var responses_default = "sealed class ApiError {\n final String message;\n fin
958
1913
  // packages/dart/src/lib/generate.ts
959
1914
  function tuneSpec(spec, schemas, refs) {
960
1915
  for (const [name, schema] of Object.entries(schemas)) {
961
- if (isRef3(schema))
1916
+ if (isRef4(schema))
962
1917
  continue;
963
- if (!isEmpty2(schema.anyOf) && !isEmpty2(schema.oneOf)) {
1918
+ if (!isEmpty3(schema.anyOf) && !isEmpty3(schema.oneOf)) {
964
1919
  delete schema.anyOf;
965
1920
  }
966
- if (!isEmpty2(schema.allOf)) {
1921
+ if (!isEmpty3(schema.allOf)) {
967
1922
  const schemas2 = schema.allOf;
968
- const refs2 = schemas2.filter(isRef3);
1923
+ const refs2 = schemas2.filter(isRef4);
969
1924
  const nonRefs = schemas2.filter(notRef2);
970
1925
  if (nonRefs.some((it) => it.type && it.type !== "object")) {
971
1926
  assert2(false, `allOf ${name} must be an object`);
@@ -980,12 +1935,12 @@ function tuneSpec(spec, schemas, refs) {
980
1935
  Object.assign(schema, objectSchema);
981
1936
  }
982
1937
  if (schema.type === "object") {
983
- if (!isEmpty2(schema.oneOf)) {
1938
+ if (!isEmpty3(schema.oneOf)) {
984
1939
  for (const oneOfIdx in schema.oneOf) {
985
1940
  const oneOf = schema.oneOf[oneOfIdx];
986
- if (isRef3(oneOf))
1941
+ if (isRef4(oneOf))
987
1942
  continue;
988
- if (!isEmpty2(oneOf.required) && schema.properties) {
1943
+ if (!isEmpty3(oneOf.required) && schema.properties) {
989
1944
  schema.oneOf[oneOfIdx] = schema.properties[oneOf.required[0]];
990
1945
  }
991
1946
  }
@@ -995,7 +1950,7 @@ function tuneSpec(spec, schemas, refs) {
995
1950
  }
996
1951
  schema.properties ??= {};
997
1952
  for (const [propName, value] of Object.entries(schema.properties)) {
998
- if (isRef3(value))
1953
+ if (isRef4(value))
999
1954
  continue;
1000
1955
  const refName = pascalcase2(`${name} ${propName.replace("[]", "")}`);
1001
1956
  refs.push({ name: refName, value });
@@ -1010,7 +1965,7 @@ function tuneSpec(spec, schemas, refs) {
1010
1965
  tuneSpec(spec, props, refs);
1011
1966
  }
1012
1967
  } else if (schema.type === "array") {
1013
- if (isRef3(schema.items))
1968
+ if (isRef4(schema.items))
1014
1969
  continue;
1015
1970
  const refName = name;
1016
1971
  refs.push({ name: refName, value: schema.items ?? {} });
@@ -1021,6 +1976,16 @@ function tuneSpec(spec, schemas, refs) {
1021
1976
  }
1022
1977
  }
1023
1978
  async function generate(spec, settings) {
1979
+ spec = "x-sdk-augmented" in spec ? spec : augmentSpec({ spec });
1980
+ settings.writer ??= writeFiles;
1981
+ settings.readFolder ??= async (folder) => {
1982
+ const files = await readdir(folder, { withFileTypes: true });
1983
+ return files.map((file) => ({
1984
+ fileName: file.name,
1985
+ filePath: join(file.parentPath, file.name),
1986
+ isFolder: file.isDirectory()
1987
+ }));
1988
+ };
1024
1989
  const clientName = settings.name || "Client";
1025
1990
  const output = join(settings.output, "lib");
1026
1991
  const groups = {};
@@ -1036,12 +2001,12 @@ async function generate(spec, settings) {
1036
2001
  if (!isSuccessStatusCode(status))
1037
2002
  continue;
1038
2003
  const response2 = operation.responses[status];
1039
- if (!isEmpty2(response2.content)) {
2004
+ if (!isEmpty3(response2.content)) {
1040
2005
  for (const [contentType, mediaType] of Object.entries(
1041
2006
  response2.content
1042
2007
  )) {
1043
2008
  if (parseJsonContentType(contentType)) {
1044
- if (mediaType.schema && !isRef3(mediaType.schema)) {
2009
+ if (mediaType.schema && !isRef4(mediaType.schema)) {
1045
2010
  const outputName = pascalcase2(`${operation.operationId} output`);
1046
2011
  spec.components.schemas[outputName] = mediaType.schema;
1047
2012
  operation.responses[status].content ??= {};
@@ -1066,7 +2031,7 @@ async function generate(spec, settings) {
1066
2031
  }
1067
2032
  group.methods.push(`
1068
2033
  Future<${response ? response.returnType : "http.StreamedResponse"}> ${camelcase3(operation.operationId)}(
1069
- ${isEmpty2(operation.requestBody) ? "" : `${input.inputName} input`}
2034
+ ${isEmpty3(operation.requestBody) ? "" : `${input.inputName} input`}
1070
2035
  ) async {
1071
2036
  final stream = await this.dispatcher.${input.contentType}(RequestConfig(
1072
2037
  method: '${entry.method}',
@@ -1131,7 +2096,7 @@ import './http.dart';
1131
2096
  ${Object.keys(groups).map((name) => `late final ${pascalcase2(name)}Client ${camelcase3(name)};`).join("\n")}
1132
2097
 
1133
2098
  ${clientName}(this.options) {
1134
- final interceptors = [BaseUrlInterceptor(() => this.options.baseUrl)];
2099
+ final interceptors = [BaseUrlInterceptor(() => this.options.baseUrl), LoggingInterceptor()];
1135
2100
  final dispatcher = Dispatcher(interceptors);
1136
2101
  final receiver = Receiver(interceptors);
1137
2102
  ${Object.keys(groups).map(
@@ -1154,39 +2119,55 @@ class Options {
1154
2119
  }
1155
2120
 
1156
2121
  `;
1157
- await writeFiles(output, {
2122
+ await settings.writer(output, {
1158
2123
  ...models,
1159
2124
  ...inputs,
1160
2125
  ...outputs
1161
2126
  });
1162
- await writeFiles(output, {
1163
- "models/index.dart": await getFolderExportsV2(join(output, "models"), {
1164
- exportSyntax: "export",
1165
- extensions: "dart"
1166
- }),
1167
- "inputs/index.dart": await getFolderExportsV2(join(output, "inputs"), {
1168
- exportSyntax: "export",
1169
- extensions: "dart"
1170
- }),
1171
- "outputs/index.dart": await getFolderExportsV2(join(output, "outputs"), {
1172
- exportSyntax: "export",
1173
- extensions: "dart"
1174
- }),
2127
+ await settings.writer(output, {
2128
+ "models/index.dart": await getFolderExportsV2(
2129
+ join(output, "models"),
2130
+ settings.readFolder,
2131
+ {
2132
+ exportSyntax: "export",
2133
+ extensions: "dart"
2134
+ }
2135
+ ),
2136
+ "inputs/index.dart": await getFolderExportsV2(
2137
+ join(output, "inputs"),
2138
+ settings.readFolder,
2139
+ {
2140
+ exportSyntax: "export",
2141
+ extensions: "dart"
2142
+ }
2143
+ ),
2144
+ "outputs/index.dart": await getFolderExportsV2(
2145
+ join(output, "outputs"),
2146
+ settings.readFolder,
2147
+ {
2148
+ exportSyntax: "export",
2149
+ extensions: "dart"
2150
+ }
2151
+ ),
1175
2152
  "interceptors.dart": interceptors_default,
1176
2153
  "http.dart": dispatcher_default,
1177
2154
  "responses.dart": responses_default,
1178
2155
  ...clazzez
1179
2156
  });
1180
- await writeFiles(output, {
1181
- "package.dart": `${await getFolderExportsV2(join(output), {
1182
- exportSyntax: "export",
1183
- extensions: "dart",
1184
- ignore(dirent) {
1185
- return dirent.isFile() && dirent.name === "package.dart";
2157
+ await settings.writer(output, {
2158
+ "package.dart": `${await getFolderExportsV2(
2159
+ join(output),
2160
+ settings.readFolder,
2161
+ {
2162
+ exportSyntax: "export",
2163
+ extensions: "dart",
2164
+ ignore(dirent) {
2165
+ return !dirent.isFolder && dirent.fileName === "package.dart";
2166
+ }
1186
2167
  }
1187
- })}${client}`
2168
+ )}${client}`
1188
2169
  });
1189
- await writeFiles(settings.output, {
2170
+ await settings.writer(settings.output, {
1190
2171
  "pubspec.yaml": {
1191
2172
  ignoreIfExists: true,
1192
2173
  content: yaml.stringify({
@@ -1211,16 +2192,18 @@ function toInputs(spec, { entry, operation }) {
1211
2192
  const inputName = pascalcase2(`${operation.operationId} input`);
1212
2193
  let contentType = "empty";
1213
2194
  let encode = "";
1214
- if (!isEmpty2(operation.requestBody)) {
1215
- const requestBody = isRef3(operation.requestBody) ? followRef3(spec, operation.requestBody.$ref) : operation.requestBody;
1216
- for (const type in requestBody.content) {
1217
- const ctSchema = isRef3(requestBody.content[type].schema) ? followRef3(spec, requestBody.content[type].schema.$ref) : requestBody.content[type].schema;
2195
+ if (!isEmpty3(operation.requestBody)) {
2196
+ for (const type in operation.requestBody.content) {
2197
+ const ctSchema = isRef4(operation.requestBody.content[type].schema) ? followRef3(spec, operation.requestBody.content[type].schema.$ref) : operation.requestBody.content[type].schema;
1218
2198
  if (!ctSchema) {
1219
2199
  console.warn(
1220
2200
  `Schema not found for ${type} in ${entry.method} ${entry.path}`
1221
2201
  );
1222
2202
  continue;
1223
2203
  }
2204
+ ctSchema.properties ??= {};
2205
+ ctSchema.required ??= [];
2206
+ patchParameters(spec, ctSchema, operation);
1224
2207
  const serializer = new DartSerializer(spec, (name, content) => {
1225
2208
  inputs[join(`inputs/${name}.dart`)] = `import 'dart:io';import 'dart:typed_data';import '../models/index.dart'; import './index.dart';
1226
2209
 
@@ -1237,6 +2220,20 @@ ${content}`;
1237
2220
  contentType = mediaType;
1238
2221
  }
1239
2222
  }
2223
+ } else {
2224
+ const ctSchema = {
2225
+ type: "object"
2226
+ };
2227
+ patchParameters(spec, ctSchema, operation);
2228
+ const serializer = new DartSerializer(spec, (name, content) => {
2229
+ inputs[join(`inputs/${name}.dart`)] = `import 'dart:io';import 'dart:typed_data';import '../models/index.dart'; import './index.dart';
2230
+
2231
+ ${content}`;
2232
+ });
2233
+ const serialized = serializer.handle(inputName, ctSchema, true, {
2234
+ alias: isObjectSchema(ctSchema) ? void 0 : inputName
2235
+ });
2236
+ encode = serialized.encode;
1240
2237
  }
1241
2238
  return { inputs, inputName, contentType, encode };
1242
2239
  }
@@ -1245,7 +2242,7 @@ function toOutput(spec, operation) {
1245
2242
  operation.responses ??= {};
1246
2243
  const outputs = {};
1247
2244
  for (const status in operation.responses) {
1248
- const response = isRef3(operation.responses[status]) ? followRef3(spec, operation.responses[status].$ref) : operation.responses[status];
2245
+ const response = isRef4(operation.responses[status]) ? followRef3(spec, operation.responses[status].$ref) : operation.responses[status];
1249
2246
  for (const type in response.content) {
1250
2247
  const { schema } = response.content[type];
1251
2248
  if (!schema) {