@typia/utils 12.0.0-dev.20260309 → 12.0.0-dev.20260310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/lib/http/internal/HttpLlmApplicationComposer.mjs +5 -1
  2. package/lib/http/internal/HttpLlmApplicationComposer.mjs.map +1 -1
  3. package/lib/index.mjs +9 -9
  4. package/lib/utils/LlmJson.mjs +9 -2
  5. package/lib/utils/LlmJson.mjs.map +1 -1
  6. package/lib/utils/internal/stringifyValidationFailure.js +17 -15
  7. package/lib/utils/internal/stringifyValidationFailure.js.map +1 -1
  8. package/lib/utils/internal/stringifyValidationFailure.mjs +17 -15
  9. package/lib/utils/internal/stringifyValidationFailure.mjs.map +1 -1
  10. package/lib/validators/internal/OpenApiOneOfValidator.mjs +5 -1
  11. package/lib/validators/internal/OpenApiOneOfValidator.mjs.map +1 -1
  12. package/package.json +2 -2
  13. package/src/converters/LlmSchemaConverter.ts +647 -647
  14. package/src/converters/OpenApiConverter.ts +285 -285
  15. package/src/converters/index.ts +5 -5
  16. package/src/converters/internal/LlmDescriptionInverter.ts +178 -178
  17. package/src/converters/internal/LlmParametersComposer.ts +52 -52
  18. package/src/converters/internal/OpenApiConstraintShifter.ts +154 -154
  19. package/src/converters/internal/OpenApiExclusiveEmender.ts +46 -46
  20. package/src/converters/internal/OpenApiV3Downgrader.ts +355 -355
  21. package/src/converters/internal/OpenApiV3Upgrader.ts +470 -470
  22. package/src/converters/internal/OpenApiV3_1Upgrader.ts +685 -685
  23. package/src/converters/internal/SwaggerV2Downgrader.ts +424 -424
  24. package/src/converters/internal/SwaggerV2Upgrader.ts +523 -523
  25. package/src/http/HttpError.ts +107 -107
  26. package/src/http/HttpLlm.ts +167 -167
  27. package/src/http/HttpMigration.ts +92 -92
  28. package/src/http/index.ts +3 -3
  29. package/src/http/internal/HttpLlmApplicationComposer.ts +361 -361
  30. package/src/http/internal/HttpLlmFunctionFetcher.ts +37 -37
  31. package/src/http/internal/HttpMigrateApplicationComposer.ts +56 -56
  32. package/src/http/internal/HttpMigrateRouteAccessor.ts +135 -135
  33. package/src/http/internal/HttpMigrateRouteComposer.ts +505 -505
  34. package/src/http/internal/HttpMigrateRouteFetcher.ts +203 -203
  35. package/src/index.ts +4 -4
  36. package/src/utils/ArrayUtil.ts +42 -42
  37. package/src/utils/LlmJson.ts +141 -141
  38. package/src/utils/MapUtil.ts +15 -15
  39. package/src/utils/NamingConvention.ts +205 -205
  40. package/src/utils/Singleton.ts +17 -17
  41. package/src/utils/StringUtil.ts +14 -14
  42. package/src/utils/dedent.ts +57 -57
  43. package/src/utils/index.ts +8 -8
  44. package/src/utils/internal/EndpointUtil.ts +44 -44
  45. package/src/utils/internal/JsonDescriptor.ts +70 -70
  46. package/src/utils/internal/OpenApiTypeCheckerBase.ts +822 -822
  47. package/src/utils/internal/coerceLlmArguments.ts +314 -314
  48. package/src/utils/internal/parseLenientJson.ts +894 -894
  49. package/src/utils/internal/stringifyValidationFailure.ts +415 -411
  50. package/src/validators/LlmTypeChecker.ts +402 -402
  51. package/src/validators/OpenApiTypeChecker.ts +297 -297
  52. package/src/validators/OpenApiV3TypeChecker.ts +70 -70
  53. package/src/validators/OpenApiV3_1TypeChecker.ts +86 -86
  54. package/src/validators/OpenApiValidator.ts +94 -94
  55. package/src/validators/SwaggerV2TypeChecker.ts +71 -71
  56. package/src/validators/functional/_isBigintString.ts +8 -8
  57. package/src/validators/functional/_isFormatByte.ts +7 -7
  58. package/src/validators/functional/_isFormatDate.ts +3 -3
  59. package/src/validators/functional/_isFormatDateTime.ts +4 -4
  60. package/src/validators/functional/_isFormatDuration.ts +4 -4
  61. package/src/validators/functional/_isFormatEmail.ts +4 -4
  62. package/src/validators/functional/_isFormatHostname.ts +4 -4
  63. package/src/validators/functional/_isFormatIdnEmail.ts +4 -4
  64. package/src/validators/functional/_isFormatIdnHostname.ts +4 -4
  65. package/src/validators/functional/_isFormatIpv4.ts +4 -4
  66. package/src/validators/functional/_isFormatIpv6.ts +4 -4
  67. package/src/validators/functional/_isFormatIri.ts +3 -3
  68. package/src/validators/functional/_isFormatIriReference.ts +4 -4
  69. package/src/validators/functional/_isFormatJsonPointer.ts +3 -3
  70. package/src/validators/functional/_isFormatPassword.ts +1 -1
  71. package/src/validators/functional/_isFormatRegex.ts +8 -8
  72. package/src/validators/functional/_isFormatRelativeJsonPointer.ts +4 -4
  73. package/src/validators/functional/_isFormatTime.ts +4 -4
  74. package/src/validators/functional/_isFormatUri.ts +6 -6
  75. package/src/validators/functional/_isFormatUriReference.ts +5 -5
  76. package/src/validators/functional/_isFormatUriTemplate.ts +4 -4
  77. package/src/validators/functional/_isFormatUrl.ts +4 -4
  78. package/src/validators/functional/_isFormatUuid.ts +3 -3
  79. package/src/validators/functional/_isUniqueItems.ts +159 -159
  80. package/src/validators/index.ts +14 -14
  81. package/src/validators/internal/IOpenApiValidatorContext.ts +17 -17
  82. package/src/validators/internal/OpenApiArrayValidator.ts +49 -49
  83. package/src/validators/internal/OpenApiBooleanValidator.ts +11 -11
  84. package/src/validators/internal/OpenApiConstantValidator.ts +11 -11
  85. package/src/validators/internal/OpenApiIntegerValidator.ts +49 -49
  86. package/src/validators/internal/OpenApiNumberValidator.ts +48 -48
  87. package/src/validators/internal/OpenApiObjectValidator.ts +83 -83
  88. package/src/validators/internal/OpenApiOneOfValidator.ts +309 -309
  89. package/src/validators/internal/OpenApiSchemaNamingRule.ts +124 -124
  90. package/src/validators/internal/OpenApiStationValidator.ts +115 -115
  91. package/src/validators/internal/OpenApiStringValidator.ts +88 -88
  92. package/src/validators/internal/OpenApiTupleValidator.ts +55 -55
@@ -1,402 +1,402 @@
1
- import { ILlmSchema } from "@typia/interface";
2
-
3
- import { MapUtil } from "../utils/MapUtil";
4
- import { OpenApiTypeCheckerBase } from "../utils/internal/OpenApiTypeCheckerBase";
5
-
6
- /**
7
- * Type checker for LLM function calling schema.
8
- *
9
- * `LlmTypeChecker` is a type checker of {@link ILlmSchema}, the type schema for
10
- * LLM (Large Language Model) function calling.
11
- *
12
- * This checker provides type guard functions for validating schema types, and
13
- * operators for traversing and comparing schemas.
14
- *
15
- * @author Jeongho Nam - https://github.com/samchon
16
- */
17
- export namespace LlmTypeChecker {
18
- /* -----------------------------------------------------------
19
- TYPE CHECKERS
20
- ----------------------------------------------------------- */
21
- /**
22
- * Test whether the schema is a null type.
23
- *
24
- * @param schema Target schema
25
- * @returns Whether null type or not
26
- */
27
- export const isNull = (schema: ILlmSchema): schema is ILlmSchema.INull =>
28
- (schema as ILlmSchema.INull).type === "null";
29
-
30
- /**
31
- * Test whether the schema is an unknown type.
32
- *
33
- * @param schema Target schema
34
- * @returns Whether unknown type or not
35
- */
36
- export const isUnknown = (
37
- schema: ILlmSchema,
38
- ): schema is ILlmSchema.IUnknown =>
39
- (schema as ILlmSchema.IUnknown).type === undefined &&
40
- !isAnyOf(schema) &&
41
- !isReference(schema);
42
-
43
- /**
44
- * Test whether the schema is a boolean type.
45
- *
46
- * @param schema Target schema
47
- * @returns Whether boolean type or not
48
- */
49
- export const isBoolean = (
50
- schema: ILlmSchema,
51
- ): schema is ILlmSchema.IBoolean =>
52
- (schema as ILlmSchema.IBoolean).type === "boolean";
53
-
54
- /**
55
- * Test whether the schema is an integer type.
56
- *
57
- * @param schema Target schema
58
- * @returns Whether integer type or not
59
- */
60
- export const isInteger = (
61
- schema: ILlmSchema,
62
- ): schema is ILlmSchema.IInteger =>
63
- (schema as ILlmSchema.IInteger).type === "integer";
64
-
65
- /**
66
- * Test whether the schema is a number type.
67
- *
68
- * @param schema Target schema
69
- * @returns Whether number type or not
70
- */
71
- export const isNumber = (schema: ILlmSchema): schema is ILlmSchema.INumber =>
72
- (schema as ILlmSchema.INumber).type === "number";
73
-
74
- /**
75
- * Test whether the schema is a string type.
76
- *
77
- * @param schema Target schema
78
- * @returns Whether string type or not
79
- */
80
- export const isString = (schema: ILlmSchema): schema is ILlmSchema.IString =>
81
- (schema as ILlmSchema.IString).type === "string";
82
-
83
- /**
84
- * Test whether the schema is an array type.
85
- *
86
- * @param schema Target schema
87
- * @returns Whether array type or not
88
- */
89
- export const isArray = (schema: ILlmSchema): schema is ILlmSchema.IArray =>
90
- (schema as ILlmSchema.IArray).type === "array" &&
91
- (schema as ILlmSchema.IArray).items !== undefined;
92
-
93
- /**
94
- * Test whether the schema is an object type.
95
- *
96
- * @param schema Target schema
97
- * @returns Whether object type or not
98
- */
99
- export const isObject = (schema: ILlmSchema): schema is ILlmSchema.IObject =>
100
- (schema as ILlmSchema.IObject).type === "object";
101
-
102
- /**
103
- * Test whether the schema is a reference type.
104
- *
105
- * @param schema Target schema
106
- * @returns Whether reference type or not
107
- */
108
- export const isReference = (
109
- schema: ILlmSchema,
110
- ): schema is ILlmSchema.IReference => (schema as any).$ref !== undefined;
111
-
112
- /**
113
- * Test whether the schema is a union type.
114
- *
115
- * @param schema Target schema
116
- * @returns Whether union type or not
117
- */
118
- export const isAnyOf = (schema: ILlmSchema): schema is ILlmSchema.IAnyOf =>
119
- (schema as ILlmSchema.IAnyOf).anyOf !== undefined;
120
-
121
- /* -----------------------------------------------------------
122
- OPERATORS
123
- ----------------------------------------------------------- */
124
- /**
125
- * Visit every nested schemas.
126
- *
127
- * Visit every nested schemas of the target, and apply the `props.closure`
128
- * function.
129
- *
130
- * Here is the list of occurring nested visitings:
131
- *
132
- * - {@link ILlmSchema.IAnyOf.anyOf}
133
- * - {@link ILlmSchema.IReference}
134
- * - {@link ILlmSchema.IObject.properties}
135
- * - {@link ILlmSchema.IArray.items}
136
- *
137
- * @param props Properties for visiting
138
- */
139
- export const visit = (props: {
140
- closure: (schema: ILlmSchema, accessor: string) => void;
141
- $defs?: Record<string, ILlmSchema> | undefined;
142
- schema: ILlmSchema;
143
- accessor?: string;
144
- refAccessor?: string;
145
- }): void => {
146
- const already: Set<string> = new Set();
147
- const refAccessor: string = props.refAccessor ?? "$input.$defs";
148
- const next = (schema: ILlmSchema, accessor: string): void => {
149
- props.closure(schema, accessor);
150
- if (LlmTypeChecker.isReference(schema)) {
151
- const key: string = schema.$ref.split("#/$defs/").pop()!;
152
- if (already.has(key) === true) return;
153
- already.add(key);
154
- const found: ILlmSchema | undefined = props.$defs?.[key];
155
- if (found !== undefined) next(found, `${refAccessor}[${key}]`);
156
- } else if (LlmTypeChecker.isAnyOf(schema))
157
- schema.anyOf.forEach((s, i) => next(s, `${accessor}.anyOf[${i}]`));
158
- else if (LlmTypeChecker.isObject(schema)) {
159
- for (const [key, value] of Object.entries(schema.properties))
160
- next(value, `${accessor}.properties[${JSON.stringify(key)}]`);
161
- if (
162
- typeof schema.additionalProperties === "object" &&
163
- schema.additionalProperties !== null
164
- )
165
- next(schema.additionalProperties, `${accessor}.additionalProperties`);
166
- } else if (LlmTypeChecker.isArray(schema))
167
- next(schema.items, `${accessor}.items`);
168
- };
169
- next(props.schema, props.accessor ?? "$input.schemas");
170
- };
171
-
172
- /**
173
- * Test whether the `x` schema covers the `y` schema.
174
- *
175
- * @param props Properties for testing
176
- * @returns Whether the `x` schema covers the `y` schema
177
- */
178
- export const covers = (props: {
179
- $defs?: Record<string, ILlmSchema> | undefined;
180
- x: ILlmSchema;
181
- y: ILlmSchema;
182
- }): boolean =>
183
- coverStation({
184
- $defs: props.$defs,
185
- x: props.x,
186
- y: props.y,
187
- visited: new Map(),
188
- });
189
-
190
- const coverStation = (p: {
191
- $defs?: Record<string, ILlmSchema> | undefined;
192
- visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
193
- x: ILlmSchema;
194
- y: ILlmSchema;
195
- }): boolean => {
196
- const cache: boolean | undefined = p.visited.get(p.x)?.get(p.y);
197
- if (cache !== undefined) return cache;
198
-
199
- // FOR RECURSIVE CASE
200
- const nested: Map<ILlmSchema, boolean> = MapUtil.take(
201
- p.visited,
202
- p.x,
203
- () => new Map(),
204
- );
205
- nested.set(p.y, true);
206
-
207
- // COMPUTE IT
208
- const result: boolean = coverSchema(p);
209
- nested.set(p.y, result);
210
- return result;
211
- };
212
-
213
- const coverSchema = (p: {
214
- $defs?: Record<string, ILlmSchema> | undefined;
215
- visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
216
- x: ILlmSchema;
217
- y: ILlmSchema;
218
- }): boolean => {
219
- // CHECK EQUALITY
220
- if (p.x === p.y) return true;
221
- else if (isReference(p.x) && isReference(p.y) && p.x.$ref === p.y.$ref)
222
- return true;
223
-
224
- // COMPARE WITH FLATTENING
225
- const alpha: ILlmSchema[] = flatSchema(p.$defs, p.x);
226
- const beta: ILlmSchema[] = flatSchema(p.$defs, p.y);
227
- if (alpha.some((x) => isUnknown(x))) return true;
228
- else if (beta.some((x) => isUnknown(x))) return false;
229
- return beta.every((b) =>
230
- alpha.some((a) =>
231
- coverEscapedSchema({
232
- $defs: p.$defs,
233
- visited: p.visited,
234
- x: a,
235
- y: b,
236
- }),
237
- ),
238
- );
239
- };
240
-
241
- const coverEscapedSchema = (p: {
242
- $defs?: Record<string, ILlmSchema> | undefined;
243
- visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
244
- x: ILlmSchema;
245
- y: ILlmSchema;
246
- }): boolean => {
247
- // CHECK EQUALITY
248
- if (p.x === p.y) return true;
249
- else if (isUnknown(p.x)) return true;
250
- else if (isUnknown(p.y)) return false;
251
- else if (isNull(p.x)) return isNull(p.y);
252
- // ATOMIC CASE
253
- else if (isBoolean(p.x)) return isBoolean(p.y) && coverBoolean(p.x, p.y);
254
- else if (isInteger(p.x)) return isInteger(p.y) && coverInteger(p.x, p.y);
255
- else if (isNumber(p.x)) return isNumber(p.y) && coverNumber(p.x, p.y);
256
- else if (isString(p.x)) return isString(p.y) && coverString(p.x, p.y);
257
- // INSTANCE CASE
258
- else if (isArray(p.x))
259
- return (
260
- isArray(p.y) &&
261
- coverArray({
262
- $defs: p.$defs,
263
- visited: p.visited,
264
- x: p.x,
265
- y: p.y,
266
- })
267
- );
268
- else if (isObject(p.x))
269
- return (
270
- isObject(p.y) &&
271
- coverObject({
272
- $defs: p.$defs,
273
- visited: p.visited,
274
- x: p.x,
275
- y: p.y,
276
- })
277
- );
278
- else if (isReference(p.x)) return isReference(p.y) && p.x.$ref === p.y.$ref;
279
- return false;
280
- };
281
-
282
- const coverArray = (p: {
283
- $defs?: Record<string, ILlmSchema> | undefined;
284
- visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
285
- x: ILlmSchema.IArray;
286
- y: ILlmSchema.IArray;
287
- }): boolean => {
288
- if (
289
- !(
290
- p.x.minItems === undefined ||
291
- (p.y.minItems !== undefined && p.x.minItems <= p.y.minItems)
292
- )
293
- )
294
- return false;
295
- else if (
296
- !(
297
- p.x.maxItems === undefined ||
298
- (p.y.maxItems !== undefined && p.x.maxItems >= p.y.maxItems)
299
- )
300
- )
301
- return false;
302
- return coverStation({
303
- $defs: p.$defs,
304
- visited: p.visited,
305
- x: p.x.items,
306
- y: p.y.items,
307
- });
308
- };
309
-
310
- const coverObject = (p: {
311
- $defs?: Record<string, ILlmSchema> | undefined;
312
- visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
313
- x: ILlmSchema.IObject;
314
- y: ILlmSchema.IObject;
315
- }): boolean => {
316
- if (!p.x.additionalProperties && !!p.y.additionalProperties) return false;
317
- else if (
318
- !!p.x.additionalProperties &&
319
- !!p.y.additionalProperties &&
320
- ((typeof p.x.additionalProperties === "object" &&
321
- p.y.additionalProperties === true) ||
322
- (typeof p.x.additionalProperties === "object" &&
323
- typeof p.y.additionalProperties === "object" &&
324
- !coverStation({
325
- $defs: p.$defs,
326
- visited: p.visited,
327
- x: p.x.additionalProperties,
328
- y: p.y.additionalProperties,
329
- })))
330
- )
331
- return false;
332
- return Object.entries(p.y.properties ?? {}).every(([key, b]) => {
333
- const a: ILlmSchema | undefined = p.x.properties?.[key];
334
- if (a === undefined) return false;
335
- else if (
336
- (p.x.required?.includes(key) ?? false) === true &&
337
- (p.y.required?.includes(key) ?? false) === false
338
- )
339
- return false;
340
- return coverStation({
341
- $defs: p.$defs,
342
- visited: p.visited,
343
- x: a,
344
- y: b,
345
- });
346
- });
347
- };
348
-
349
- const coverBoolean = (
350
- x: ILlmSchema.IBoolean,
351
- y: ILlmSchema.IBoolean,
352
- ): boolean => {
353
- if (!!x.enum?.length)
354
- return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
355
- return true;
356
- };
357
-
358
- const coverInteger = (
359
- x: ILlmSchema.IInteger,
360
- y: ILlmSchema.IInteger,
361
- ): boolean => {
362
- if (!!x.enum?.length)
363
- return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
364
- return OpenApiTypeCheckerBase.coverInteger(x, y);
365
- };
366
-
367
- const coverNumber = (
368
- x: ILlmSchema.INumber,
369
- y: ILlmSchema.IInteger | ILlmSchema.INumber,
370
- ): boolean => {
371
- if (!!x.enum?.length)
372
- return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
373
- return OpenApiTypeCheckerBase.coverNumber(x, y);
374
- };
375
-
376
- const coverString = (
377
- x: ILlmSchema.IString,
378
- y: ILlmSchema.IString,
379
- ): boolean => {
380
- if (!!x.enum?.length)
381
- return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
382
- return OpenApiTypeCheckerBase.coverString(x, y);
383
- };
384
-
385
- const flatSchema = (
386
- $defs: Record<string, ILlmSchema> | undefined,
387
- schema: ILlmSchema,
388
- ): ILlmSchema[] => {
389
- schema = escapeReference($defs, schema);
390
- if (isAnyOf(schema))
391
- return schema.anyOf.map((v) => flatSchema($defs, v)).flat();
392
- return [schema];
393
- };
394
-
395
- const escapeReference = (
396
- $defs: Record<string, ILlmSchema> | undefined,
397
- schema: ILlmSchema,
398
- ): Exclude<ILlmSchema, ILlmSchema.IReference> =>
399
- isReference(schema)
400
- ? escapeReference($defs, $defs![schema.$ref.replace("#/$defs/", "")]!)
401
- : schema;
402
- }
1
+ import { ILlmSchema } from "@typia/interface";
2
+
3
+ import { MapUtil } from "../utils/MapUtil";
4
+ import { OpenApiTypeCheckerBase } from "../utils/internal/OpenApiTypeCheckerBase";
5
+
6
+ /**
7
+ * Type checker for LLM function calling schema.
8
+ *
9
+ * `LlmTypeChecker` is a type checker of {@link ILlmSchema}, the type schema for
10
+ * LLM (Large Language Model) function calling.
11
+ *
12
+ * This checker provides type guard functions for validating schema types, and
13
+ * operators for traversing and comparing schemas.
14
+ *
15
+ * @author Jeongho Nam - https://github.com/samchon
16
+ */
17
+ export namespace LlmTypeChecker {
18
+ /* -----------------------------------------------------------
19
+ TYPE CHECKERS
20
+ ----------------------------------------------------------- */
21
+ /**
22
+ * Test whether the schema is a null type.
23
+ *
24
+ * @param schema Target schema
25
+ * @returns Whether null type or not
26
+ */
27
+ export const isNull = (schema: ILlmSchema): schema is ILlmSchema.INull =>
28
+ (schema as ILlmSchema.INull).type === "null";
29
+
30
+ /**
31
+ * Test whether the schema is an unknown type.
32
+ *
33
+ * @param schema Target schema
34
+ * @returns Whether unknown type or not
35
+ */
36
+ export const isUnknown = (
37
+ schema: ILlmSchema,
38
+ ): schema is ILlmSchema.IUnknown =>
39
+ (schema as ILlmSchema.IUnknown).type === undefined &&
40
+ !isAnyOf(schema) &&
41
+ !isReference(schema);
42
+
43
+ /**
44
+ * Test whether the schema is a boolean type.
45
+ *
46
+ * @param schema Target schema
47
+ * @returns Whether boolean type or not
48
+ */
49
+ export const isBoolean = (
50
+ schema: ILlmSchema,
51
+ ): schema is ILlmSchema.IBoolean =>
52
+ (schema as ILlmSchema.IBoolean).type === "boolean";
53
+
54
+ /**
55
+ * Test whether the schema is an integer type.
56
+ *
57
+ * @param schema Target schema
58
+ * @returns Whether integer type or not
59
+ */
60
+ export const isInteger = (
61
+ schema: ILlmSchema,
62
+ ): schema is ILlmSchema.IInteger =>
63
+ (schema as ILlmSchema.IInteger).type === "integer";
64
+
65
+ /**
66
+ * Test whether the schema is a number type.
67
+ *
68
+ * @param schema Target schema
69
+ * @returns Whether number type or not
70
+ */
71
+ export const isNumber = (schema: ILlmSchema): schema is ILlmSchema.INumber =>
72
+ (schema as ILlmSchema.INumber).type === "number";
73
+
74
+ /**
75
+ * Test whether the schema is a string type.
76
+ *
77
+ * @param schema Target schema
78
+ * @returns Whether string type or not
79
+ */
80
+ export const isString = (schema: ILlmSchema): schema is ILlmSchema.IString =>
81
+ (schema as ILlmSchema.IString).type === "string";
82
+
83
+ /**
84
+ * Test whether the schema is an array type.
85
+ *
86
+ * @param schema Target schema
87
+ * @returns Whether array type or not
88
+ */
89
+ export const isArray = (schema: ILlmSchema): schema is ILlmSchema.IArray =>
90
+ (schema as ILlmSchema.IArray).type === "array" &&
91
+ (schema as ILlmSchema.IArray).items !== undefined;
92
+
93
+ /**
94
+ * Test whether the schema is an object type.
95
+ *
96
+ * @param schema Target schema
97
+ * @returns Whether object type or not
98
+ */
99
+ export const isObject = (schema: ILlmSchema): schema is ILlmSchema.IObject =>
100
+ (schema as ILlmSchema.IObject).type === "object";
101
+
102
+ /**
103
+ * Test whether the schema is a reference type.
104
+ *
105
+ * @param schema Target schema
106
+ * @returns Whether reference type or not
107
+ */
108
+ export const isReference = (
109
+ schema: ILlmSchema,
110
+ ): schema is ILlmSchema.IReference => (schema as any).$ref !== undefined;
111
+
112
+ /**
113
+ * Test whether the schema is a union type.
114
+ *
115
+ * @param schema Target schema
116
+ * @returns Whether union type or not
117
+ */
118
+ export const isAnyOf = (schema: ILlmSchema): schema is ILlmSchema.IAnyOf =>
119
+ (schema as ILlmSchema.IAnyOf).anyOf !== undefined;
120
+
121
+ /* -----------------------------------------------------------
122
+ OPERATORS
123
+ ----------------------------------------------------------- */
124
+ /**
125
+ * Visit every nested schemas.
126
+ *
127
+ * Visit every nested schemas of the target, and apply the `props.closure`
128
+ * function.
129
+ *
130
+ * Here is the list of occurring nested visitings:
131
+ *
132
+ * - {@link ILlmSchema.IAnyOf.anyOf}
133
+ * - {@link ILlmSchema.IReference}
134
+ * - {@link ILlmSchema.IObject.properties}
135
+ * - {@link ILlmSchema.IArray.items}
136
+ *
137
+ * @param props Properties for visiting
138
+ */
139
+ export const visit = (props: {
140
+ closure: (schema: ILlmSchema, accessor: string) => void;
141
+ $defs?: Record<string, ILlmSchema> | undefined;
142
+ schema: ILlmSchema;
143
+ accessor?: string;
144
+ refAccessor?: string;
145
+ }): void => {
146
+ const already: Set<string> = new Set();
147
+ const refAccessor: string = props.refAccessor ?? "$input.$defs";
148
+ const next = (schema: ILlmSchema, accessor: string): void => {
149
+ props.closure(schema, accessor);
150
+ if (LlmTypeChecker.isReference(schema)) {
151
+ const key: string = schema.$ref.split("#/$defs/").pop()!;
152
+ if (already.has(key) === true) return;
153
+ already.add(key);
154
+ const found: ILlmSchema | undefined = props.$defs?.[key];
155
+ if (found !== undefined) next(found, `${refAccessor}[${key}]`);
156
+ } else if (LlmTypeChecker.isAnyOf(schema))
157
+ schema.anyOf.forEach((s, i) => next(s, `${accessor}.anyOf[${i}]`));
158
+ else if (LlmTypeChecker.isObject(schema)) {
159
+ for (const [key, value] of Object.entries(schema.properties))
160
+ next(value, `${accessor}.properties[${JSON.stringify(key)}]`);
161
+ if (
162
+ typeof schema.additionalProperties === "object" &&
163
+ schema.additionalProperties !== null
164
+ )
165
+ next(schema.additionalProperties, `${accessor}.additionalProperties`);
166
+ } else if (LlmTypeChecker.isArray(schema))
167
+ next(schema.items, `${accessor}.items`);
168
+ };
169
+ next(props.schema, props.accessor ?? "$input.schemas");
170
+ };
171
+
172
+ /**
173
+ * Test whether the `x` schema covers the `y` schema.
174
+ *
175
+ * @param props Properties for testing
176
+ * @returns Whether the `x` schema covers the `y` schema
177
+ */
178
+ export const covers = (props: {
179
+ $defs?: Record<string, ILlmSchema> | undefined;
180
+ x: ILlmSchema;
181
+ y: ILlmSchema;
182
+ }): boolean =>
183
+ coverStation({
184
+ $defs: props.$defs,
185
+ x: props.x,
186
+ y: props.y,
187
+ visited: new Map(),
188
+ });
189
+
190
+ const coverStation = (p: {
191
+ $defs?: Record<string, ILlmSchema> | undefined;
192
+ visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
193
+ x: ILlmSchema;
194
+ y: ILlmSchema;
195
+ }): boolean => {
196
+ const cache: boolean | undefined = p.visited.get(p.x)?.get(p.y);
197
+ if (cache !== undefined) return cache;
198
+
199
+ // FOR RECURSIVE CASE
200
+ const nested: Map<ILlmSchema, boolean> = MapUtil.take(
201
+ p.visited,
202
+ p.x,
203
+ () => new Map(),
204
+ );
205
+ nested.set(p.y, true);
206
+
207
+ // COMPUTE IT
208
+ const result: boolean = coverSchema(p);
209
+ nested.set(p.y, result);
210
+ return result;
211
+ };
212
+
213
+ const coverSchema = (p: {
214
+ $defs?: Record<string, ILlmSchema> | undefined;
215
+ visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
216
+ x: ILlmSchema;
217
+ y: ILlmSchema;
218
+ }): boolean => {
219
+ // CHECK EQUALITY
220
+ if (p.x === p.y) return true;
221
+ else if (isReference(p.x) && isReference(p.y) && p.x.$ref === p.y.$ref)
222
+ return true;
223
+
224
+ // COMPARE WITH FLATTENING
225
+ const alpha: ILlmSchema[] = flatSchema(p.$defs, p.x);
226
+ const beta: ILlmSchema[] = flatSchema(p.$defs, p.y);
227
+ if (alpha.some((x) => isUnknown(x))) return true;
228
+ else if (beta.some((x) => isUnknown(x))) return false;
229
+ return beta.every((b) =>
230
+ alpha.some((a) =>
231
+ coverEscapedSchema({
232
+ $defs: p.$defs,
233
+ visited: p.visited,
234
+ x: a,
235
+ y: b,
236
+ }),
237
+ ),
238
+ );
239
+ };
240
+
241
+ const coverEscapedSchema = (p: {
242
+ $defs?: Record<string, ILlmSchema> | undefined;
243
+ visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
244
+ x: ILlmSchema;
245
+ y: ILlmSchema;
246
+ }): boolean => {
247
+ // CHECK EQUALITY
248
+ if (p.x === p.y) return true;
249
+ else if (isUnknown(p.x)) return true;
250
+ else if (isUnknown(p.y)) return false;
251
+ else if (isNull(p.x)) return isNull(p.y);
252
+ // ATOMIC CASE
253
+ else if (isBoolean(p.x)) return isBoolean(p.y) && coverBoolean(p.x, p.y);
254
+ else if (isInteger(p.x)) return isInteger(p.y) && coverInteger(p.x, p.y);
255
+ else if (isNumber(p.x)) return isNumber(p.y) && coverNumber(p.x, p.y);
256
+ else if (isString(p.x)) return isString(p.y) && coverString(p.x, p.y);
257
+ // INSTANCE CASE
258
+ else if (isArray(p.x))
259
+ return (
260
+ isArray(p.y) &&
261
+ coverArray({
262
+ $defs: p.$defs,
263
+ visited: p.visited,
264
+ x: p.x,
265
+ y: p.y,
266
+ })
267
+ );
268
+ else if (isObject(p.x))
269
+ return (
270
+ isObject(p.y) &&
271
+ coverObject({
272
+ $defs: p.$defs,
273
+ visited: p.visited,
274
+ x: p.x,
275
+ y: p.y,
276
+ })
277
+ );
278
+ else if (isReference(p.x)) return isReference(p.y) && p.x.$ref === p.y.$ref;
279
+ return false;
280
+ };
281
+
282
+ const coverArray = (p: {
283
+ $defs?: Record<string, ILlmSchema> | undefined;
284
+ visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
285
+ x: ILlmSchema.IArray;
286
+ y: ILlmSchema.IArray;
287
+ }): boolean => {
288
+ if (
289
+ !(
290
+ p.x.minItems === undefined ||
291
+ (p.y.minItems !== undefined && p.x.minItems <= p.y.minItems)
292
+ )
293
+ )
294
+ return false;
295
+ else if (
296
+ !(
297
+ p.x.maxItems === undefined ||
298
+ (p.y.maxItems !== undefined && p.x.maxItems >= p.y.maxItems)
299
+ )
300
+ )
301
+ return false;
302
+ return coverStation({
303
+ $defs: p.$defs,
304
+ visited: p.visited,
305
+ x: p.x.items,
306
+ y: p.y.items,
307
+ });
308
+ };
309
+
310
+ const coverObject = (p: {
311
+ $defs?: Record<string, ILlmSchema> | undefined;
312
+ visited: Map<ILlmSchema, Map<ILlmSchema, boolean>>;
313
+ x: ILlmSchema.IObject;
314
+ y: ILlmSchema.IObject;
315
+ }): boolean => {
316
+ if (!p.x.additionalProperties && !!p.y.additionalProperties) return false;
317
+ else if (
318
+ !!p.x.additionalProperties &&
319
+ !!p.y.additionalProperties &&
320
+ ((typeof p.x.additionalProperties === "object" &&
321
+ p.y.additionalProperties === true) ||
322
+ (typeof p.x.additionalProperties === "object" &&
323
+ typeof p.y.additionalProperties === "object" &&
324
+ !coverStation({
325
+ $defs: p.$defs,
326
+ visited: p.visited,
327
+ x: p.x.additionalProperties,
328
+ y: p.y.additionalProperties,
329
+ })))
330
+ )
331
+ return false;
332
+ return Object.entries(p.y.properties ?? {}).every(([key, b]) => {
333
+ const a: ILlmSchema | undefined = p.x.properties?.[key];
334
+ if (a === undefined) return false;
335
+ else if (
336
+ (p.x.required?.includes(key) ?? false) === true &&
337
+ (p.y.required?.includes(key) ?? false) === false
338
+ )
339
+ return false;
340
+ return coverStation({
341
+ $defs: p.$defs,
342
+ visited: p.visited,
343
+ x: a,
344
+ y: b,
345
+ });
346
+ });
347
+ };
348
+
349
+ const coverBoolean = (
350
+ x: ILlmSchema.IBoolean,
351
+ y: ILlmSchema.IBoolean,
352
+ ): boolean => {
353
+ if (!!x.enum?.length)
354
+ return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
355
+ return true;
356
+ };
357
+
358
+ const coverInteger = (
359
+ x: ILlmSchema.IInteger,
360
+ y: ILlmSchema.IInteger,
361
+ ): boolean => {
362
+ if (!!x.enum?.length)
363
+ return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
364
+ return OpenApiTypeCheckerBase.coverInteger(x, y);
365
+ };
366
+
367
+ const coverNumber = (
368
+ x: ILlmSchema.INumber,
369
+ y: ILlmSchema.IInteger | ILlmSchema.INumber,
370
+ ): boolean => {
371
+ if (!!x.enum?.length)
372
+ return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
373
+ return OpenApiTypeCheckerBase.coverNumber(x, y);
374
+ };
375
+
376
+ const coverString = (
377
+ x: ILlmSchema.IString,
378
+ y: ILlmSchema.IString,
379
+ ): boolean => {
380
+ if (!!x.enum?.length)
381
+ return !!y.enum?.length && y.enum.every((v) => x.enum!.includes(v));
382
+ return OpenApiTypeCheckerBase.coverString(x, y);
383
+ };
384
+
385
+ const flatSchema = (
386
+ $defs: Record<string, ILlmSchema> | undefined,
387
+ schema: ILlmSchema,
388
+ ): ILlmSchema[] => {
389
+ schema = escapeReference($defs, schema);
390
+ if (isAnyOf(schema))
391
+ return schema.anyOf.map((v) => flatSchema($defs, v)).flat();
392
+ return [schema];
393
+ };
394
+
395
+ const escapeReference = (
396
+ $defs: Record<string, ILlmSchema> | undefined,
397
+ schema: ILlmSchema,
398
+ ): Exclude<ILlmSchema, ILlmSchema.IReference> =>
399
+ isReference(schema)
400
+ ? escapeReference($defs, $defs![schema.$ref.replace("#/$defs/", "")]!)
401
+ : schema;
402
+ }