pi-commandcode-provider 0.4.3 → 0.5.1

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,382 @@
1
+ function isRecord(value: unknown): value is Record<string, unknown> {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value)
3
+ }
4
+
5
+ function stringValue(value: unknown): string | undefined {
6
+ return typeof value === "string" ? value : undefined
7
+ }
8
+
9
+ function booleanValue(value: unknown): boolean | undefined {
10
+ return typeof value === "boolean" ? value : undefined
11
+ }
12
+
13
+ type JsonSchemaValue = boolean | Record<string, unknown>
14
+
15
+ const JSON_SCHEMA_TYPES = new Set([
16
+ "array",
17
+ "boolean",
18
+ "integer",
19
+ "null",
20
+ "number",
21
+ "object",
22
+ "string",
23
+ ])
24
+
25
+ const LEGACY_KINDS = new Set([
26
+ "any",
27
+ "array",
28
+ "boolean",
29
+ "enum",
30
+ "integer",
31
+ "intersect",
32
+ "intersection",
33
+ "literal",
34
+ "never",
35
+ "null",
36
+ "nullable",
37
+ "number",
38
+ "object",
39
+ "optional",
40
+ "string",
41
+ "undefined",
42
+ "union",
43
+ "unknown",
44
+ ])
45
+
46
+ const LEGACY_FIELDS = new Set([
47
+ "element",
48
+ "kind",
49
+ "inner",
50
+ "optional",
51
+ "value",
52
+ "values",
53
+ "variants",
54
+ "wrapped",
55
+ ])
56
+
57
+ const SCHEMA_MAP_FIELDS = new Set([
58
+ "$defs",
59
+ "definitions",
60
+ "dependentSchemas",
61
+ "patternProperties",
62
+ "properties",
63
+ ])
64
+
65
+ const SCHEMA_ARRAY_FIELDS = new Set(["allOf", "anyOf", "oneOf", "prefixItems"])
66
+
67
+ const SCHEMA_VALUE_FIELDS = new Set([
68
+ "additionalItems",
69
+ "additionalProperties",
70
+ "contains",
71
+ "contentSchema",
72
+ "else",
73
+ "if",
74
+ "items",
75
+ "not",
76
+ "propertyNames",
77
+ "then",
78
+ "unevaluatedItems",
79
+ "unevaluatedProperties",
80
+ ])
81
+
82
+ const SCHEMA_KEYWORDS = new Set([
83
+ "$anchor",
84
+ "$comment",
85
+ "$defs",
86
+ "$dynamicAnchor",
87
+ "$dynamicRef",
88
+ "$id",
89
+ "$ref",
90
+ "$schema",
91
+ "$vocabulary",
92
+ "additionalItems",
93
+ "additionalProperties",
94
+ "allOf",
95
+ "anyOf",
96
+ "const",
97
+ "contains",
98
+ "contentEncoding",
99
+ "contentMediaType",
100
+ "contentSchema",
101
+ "default",
102
+ "definitions",
103
+ "dependentRequired",
104
+ "dependentSchemas",
105
+ "description",
106
+ "else",
107
+ "enum",
108
+ "examples",
109
+ "exclusiveMaximum",
110
+ "exclusiveMinimum",
111
+ "format",
112
+ "if",
113
+ "items",
114
+ "maxContains",
115
+ "maxItems",
116
+ "maxLength",
117
+ "maxProperties",
118
+ "maximum",
119
+ "minContains",
120
+ "minItems",
121
+ "minLength",
122
+ "minProperties",
123
+ "minimum",
124
+ "multipleOf",
125
+ "not",
126
+ "oneOf",
127
+ "pattern",
128
+ "patternProperties",
129
+ "prefixItems",
130
+ "properties",
131
+ "propertyNames",
132
+ "readOnly",
133
+ "required",
134
+ "title",
135
+ "type",
136
+ "unevaluatedItems",
137
+ "unevaluatedProperties",
138
+ "uniqueItems",
139
+ "writeOnly",
140
+ ])
141
+
142
+ function stringArray(value: unknown): string[] | undefined {
143
+ if (!Array.isArray(value)) return undefined
144
+ const values = value.filter((item): item is string => typeof item === "string")
145
+ return values.length === value.length ? values : undefined
146
+ }
147
+
148
+ function validSchemaType(value: unknown): boolean {
149
+ if (typeof value === "string") return JSON_SCHEMA_TYPES.has(value)
150
+ if (!Array.isArray(value) || value.length === 0) return false
151
+ return value.every((item) => typeof item === "string" && JSON_SCHEMA_TYPES.has(item))
152
+ }
153
+
154
+ function legacyKind(schema: Record<string, unknown>): string | undefined {
155
+ const explicitKind = stringValue(schema.kind)?.toLowerCase()
156
+ if (explicitKind && LEGACY_KINDS.has(explicitKind)) return explicitKind
157
+
158
+ const type = stringValue(schema.type)
159
+ const normalized = type?.toLowerCase()
160
+ if (!normalized || !LEGACY_KINDS.has(normalized)) return undefined
161
+ if (!validSchemaType(type) || Object.keys(schema).some((key) => LEGACY_FIELDS.has(key))) {
162
+ return normalized
163
+ }
164
+ return undefined
165
+ }
166
+
167
+ function looksLikeJsonSchema(schema: Record<string, unknown>): boolean {
168
+ if (Object.keys(schema).length === 0) return true
169
+ if (schema.type !== undefined && !validSchemaType(schema.type)) return false
170
+ return Object.keys(schema).some((key) => SCHEMA_KEYWORDS.has(key))
171
+ }
172
+
173
+ function isOptionalSchema(schema: unknown): boolean {
174
+ if (!isRecord(schema)) return false
175
+ if (booleanValue(schema.optional) === true) return true
176
+
177
+ const kind = legacyKind(schema)
178
+ if (kind === "optional") return true
179
+ if (kind !== "union") return false
180
+
181
+ const variants = Array.isArray(schema.variants)
182
+ ? schema.variants
183
+ : Array.isArray(schema.anyOf)
184
+ ? schema.anyOf
185
+ : []
186
+ return variants.some((variant) => legacyKind(isRecord(variant) ? variant : {}) === "undefined")
187
+ }
188
+
189
+ function schemaValue(value: unknown, seen: WeakSet<object>): JsonSchemaValue {
190
+ if (typeof value === "boolean") return value
191
+ if (!isRecord(value)) return {}
192
+ return convertSchema(value, seen)
193
+ }
194
+
195
+ function setSchemaProperty(target: Record<string, unknown>, key: string, value: unknown): void {
196
+ Object.defineProperty(target, key, {
197
+ configurable: true,
198
+ enumerable: true,
199
+ value,
200
+ writable: true,
201
+ })
202
+ }
203
+
204
+ function schemaMap(value: unknown, seen: WeakSet<object>): Record<string, unknown> {
205
+ if (!isRecord(value)) return {}
206
+ const out: Record<string, unknown> = {}
207
+ for (const [key, item] of Object.entries(value)) {
208
+ setSchemaProperty(out, key, schemaValue(item, seen))
209
+ }
210
+ return out
211
+ }
212
+
213
+ function schemaArray(value: unknown, seen: WeakSet<object>): unknown[] {
214
+ if (!Array.isArray(value)) return []
215
+ return value.map((item) => schemaValue(item, seen))
216
+ }
217
+
218
+ function isSchemaValue(value: unknown): value is JsonSchemaValue {
219
+ return typeof value === "boolean" || isRecord(value)
220
+ }
221
+
222
+ function copySchemaObject(
223
+ source: Record<string, unknown>,
224
+ seen: WeakSet<object>,
225
+ legacy: boolean,
226
+ forcedType?: string,
227
+ ): JsonSchemaValue {
228
+ const out: Record<string, unknown> = {}
229
+
230
+ for (const [key, value] of Object.entries(source)) {
231
+ if (legacy && LEGACY_FIELDS.has(key)) continue
232
+ if (key === "nullable" || (forcedType !== undefined && key === "type")) continue
233
+
234
+ if (key === "required") {
235
+ const required = stringArray(value)
236
+ if (required) out.required = required
237
+ } else if (SCHEMA_MAP_FIELDS.has(key)) {
238
+ out[key] = schemaMap(value, seen)
239
+ } else if (SCHEMA_ARRAY_FIELDS.has(key)) {
240
+ out[key] = schemaArray(value, seen)
241
+ } else if (SCHEMA_VALUE_FIELDS.has(key)) {
242
+ out[key] =
243
+ Array.isArray(value) && key === "items"
244
+ ? schemaArray(value, seen)
245
+ : schemaValue(value, seen)
246
+ } else {
247
+ out[key] = value
248
+ }
249
+ }
250
+
251
+ if (forcedType !== undefined) out.type = forcedType
252
+ if (booleanValue(source.nullable) === true) return makeNullable(out)
253
+ return out
254
+ }
255
+
256
+ function makeNullable(schema: Record<string, unknown>): Record<string, unknown> {
257
+ const type = schema.type
258
+ if (typeof type === "string") {
259
+ if (type === "null") return schema
260
+ return { ...schema, type: [type, "null"] }
261
+ }
262
+ if (Array.isArray(type) && !type.includes("null")) {
263
+ return { ...schema, type: [...type, "null"] }
264
+ }
265
+ if (Array.isArray(schema.anyOf)) {
266
+ return { ...schema, anyOf: [...schema.anyOf, { type: "null" }] }
267
+ }
268
+ return { anyOf: [schema, { type: "null" }] }
269
+ }
270
+
271
+ function legacyVariants(schema: Record<string, unknown>): unknown[] {
272
+ if (Array.isArray(schema.variants)) return schema.variants
273
+ if (Array.isArray(schema.anyOf)) return schema.anyOf
274
+ return []
275
+ }
276
+
277
+ function convertLegacySchema(
278
+ source: Record<string, unknown>,
279
+ kind: string,
280
+ seen: WeakSet<object>,
281
+ ): JsonSchemaValue {
282
+ if (kind === "optional") return schemaValue(source.wrapped ?? source.inner, seen)
283
+ if (kind === "nullable") {
284
+ const wrapped = schemaValue(source.wrapped ?? source.inner, seen)
285
+ return typeof wrapped === "boolean" ? wrapped : makeNullable(wrapped)
286
+ }
287
+ if (kind === "undefined" || kind === "never" || kind === "any" || kind === "unknown") return {}
288
+
289
+ if (kind === "union" || kind === "intersect" || kind === "intersection") {
290
+ const variants = legacyVariants(source)
291
+ .map((variant) => schemaValue(variant, seen))
292
+ .filter(
293
+ (variant) =>
294
+ isSchemaValue(variant) &&
295
+ (typeof variant === "boolean" || Object.keys(variant).length > 0),
296
+ )
297
+ if (variants.length === 0) return copySchemaObject(source, seen, true)
298
+ if (variants.length === 1) return variants[0] ?? {}
299
+
300
+ const out = copySchemaObject(source, seen, true)
301
+ if (typeof out !== "boolean") out[kind === "union" ? "anyOf" : "allOf"] = variants
302
+ return out
303
+ }
304
+
305
+ if (kind === "object") {
306
+ const converted = copySchemaObject(source, seen, true, "object")
307
+ if (typeof converted === "boolean") return converted
308
+ const out = converted
309
+ const sourceProperties = isRecord(source.properties) ? source.properties : undefined
310
+ if (!sourceProperties) return out
311
+
312
+ const properties: Record<string, unknown> = {}
313
+ const optional = stringArray(source.optional) ?? []
314
+ for (const [key, value] of Object.entries(sourceProperties)) {
315
+ setSchemaProperty(properties, key, schemaValue(value, seen))
316
+ }
317
+ out.properties = properties
318
+
319
+ const explicitRequired = stringArray(source.required)
320
+ const required =
321
+ explicitRequired ??
322
+ Object.entries(sourceProperties)
323
+ .filter(([key, value]) => !optional.includes(key) && !isOptionalSchema(value))
324
+ .map(([key]) => key)
325
+ if (required.length > 0) out.required = required
326
+ else delete out.required
327
+ return out
328
+ }
329
+
330
+ if (kind === "array") {
331
+ const converted = copySchemaObject(source, seen, true, "array")
332
+ if (typeof converted === "boolean") return converted
333
+ const out = converted
334
+ if (!("items" in source) && "element" in source) out.items = schemaValue(source.element, seen)
335
+ return out
336
+ }
337
+
338
+ if (kind === "enum") {
339
+ const converted = copySchemaObject(source, seen, true)
340
+ if (typeof converted === "boolean") return converted
341
+ const out = converted
342
+ if (!("enum" in out) && Array.isArray(source.values)) out.enum = source.values
343
+ return out
344
+ }
345
+
346
+ if (kind === "literal") {
347
+ const converted = copySchemaObject(source, seen, true)
348
+ if (typeof converted === "boolean") return converted
349
+ const out = converted
350
+ if (!("const" in out) && "value" in source) out.const = source.value
351
+ return out
352
+ }
353
+
354
+ const scalarType =
355
+ kind === "string" ||
356
+ kind === "number" ||
357
+ kind === "boolean" ||
358
+ kind === "integer" ||
359
+ kind === "null"
360
+ ? kind
361
+ : undefined
362
+ return scalarType ? copySchemaObject(source, seen, true, scalarType) : {}
363
+ }
364
+
365
+ function convertSchema(source: Record<string, unknown>, seen: WeakSet<object>): JsonSchemaValue {
366
+ if (seen.has(source)) return {}
367
+ seen.add(source)
368
+ try {
369
+ const kind = legacyKind(source)
370
+ if (kind) return convertLegacySchema(source, kind, seen)
371
+ if (!looksLikeJsonSchema(source)) return {}
372
+ return copySchemaObject(source, seen, false)
373
+ } finally {
374
+ seen.delete(source)
375
+ }
376
+ }
377
+
378
+ export function toJsonSchema(schema: unknown): unknown {
379
+ if (typeof schema === "boolean") return schema
380
+ if (!isRecord(schema)) return {}
381
+ return convertSchema(schema, new WeakSet<object>())
382
+ }