structured-outputs 0.1.0-beta.22 → 0.1.0-beta.23

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 (111) hide show
  1. package/README.md +1 -1
  2. package/esm/ResponseFormat.d.ts +8 -8
  3. package/esm/ResponseFormat.d.ts.map +1 -1
  4. package/esm/ResponseFormat.js +4 -7
  5. package/esm/ResponseFormat.js.map +1 -1
  6. package/esm/Tool.d.ts +2 -3
  7. package/esm/Tool.d.ts.map +1 -1
  8. package/esm/Tool.js +2 -3
  9. package/esm/Tool.js.map +1 -1
  10. package/esm/types/Ty.d.ts +19 -12
  11. package/esm/types/Ty.d.ts.map +1 -1
  12. package/esm/types/Ty.js +28 -7
  13. package/esm/types/Ty.js.map +1 -1
  14. package/esm/types/array.d.ts +1 -1
  15. package/esm/types/array.d.ts.map +1 -1
  16. package/esm/types/array.js +1 -1
  17. package/esm/types/array.js.map +1 -1
  18. package/esm/types/constantUnion.d.ts +1 -1
  19. package/esm/types/constantUnion.d.ts.map +1 -1
  20. package/esm/types/constantUnion.js +1 -1
  21. package/esm/types/constantUnion.js.map +1 -1
  22. package/esm/types/mod.d.ts +2 -3
  23. package/esm/types/mod.d.ts.map +1 -1
  24. package/esm/types/mod.js +2 -3
  25. package/esm/types/mod.js.map +1 -1
  26. package/esm/types/object.d.ts +3 -4
  27. package/esm/types/object.d.ts.map +1 -1
  28. package/esm/types/object.js +3 -3
  29. package/esm/types/object.js.map +1 -1
  30. package/esm/types/primitives.d.ts +4 -4
  31. package/esm/types/primitives.d.ts.map +1 -1
  32. package/esm/types/primitives.js +4 -4
  33. package/esm/types/primitives.js.map +1 -1
  34. package/esm/types/std/Date.d.ts +4 -0
  35. package/esm/types/std/Date.d.ts.map +1 -0
  36. package/esm/types/std/Date.js +14 -0
  37. package/esm/types/std/Date.js.map +1 -0
  38. package/esm/types/std/Option.d.ts +3 -2
  39. package/esm/types/std/Option.d.ts.map +1 -1
  40. package/esm/types/std/Option.js +1 -1
  41. package/esm/types/std/color.d.ts +8 -0
  42. package/esm/types/std/color.d.ts.map +1 -0
  43. package/esm/types/std/color.js +13 -0
  44. package/esm/types/std/color.js.map +1 -0
  45. package/esm/types/std/mod.d.ts +2 -0
  46. package/esm/types/std/mod.d.ts.map +1 -1
  47. package/esm/types/std/mod.js +2 -0
  48. package/esm/types/std/mod.js.map +1 -1
  49. package/esm/types/taggedUnion.d.ts +1 -1
  50. package/esm/types/taggedUnion.d.ts.map +1 -1
  51. package/esm/types/taggedUnion.js +20 -14
  52. package/esm/types/taggedUnion.js.map +1 -1
  53. package/esm/types/transform.d.ts +3 -0
  54. package/esm/types/transform.d.ts.map +1 -0
  55. package/esm/types/transform.js +5 -0
  56. package/esm/types/transform.js.map +1 -0
  57. package/esm/types/tuple.d.ts +5 -0
  58. package/esm/types/tuple.d.ts.map +1 -0
  59. package/esm/types/tuple.js +11 -0
  60. package/esm/types/tuple.js.map +1 -0
  61. package/esm/util/recombine.d.ts +2 -0
  62. package/esm/util/recombine.d.ts.map +1 -0
  63. package/esm/util/recombine.js +4 -0
  64. package/esm/util/recombine.js.map +1 -0
  65. package/package.json +1 -1
  66. package/src/ResponseFormat.ts +14 -17
  67. package/src/Tool.ts +5 -6
  68. package/src/types/Ty.ts +71 -30
  69. package/src/types/array.ts +9 -5
  70. package/src/types/constantUnion.ts +2 -2
  71. package/src/types/mod.ts +2 -3
  72. package/src/types/object.ts +15 -9
  73. package/src/types/primitives.ts +8 -8
  74. package/src/types/std/Date.ts +19 -0
  75. package/src/types/std/Option.ts +2 -2
  76. package/src/types/std/color.ts +27 -0
  77. package/src/types/std/mod.ts +2 -0
  78. package/src/types/taggedUnion.ts +28 -15
  79. package/src/types/transform.ts +8 -0
  80. package/src/types/tuple.ts +17 -0
  81. package/src/util/recombine.ts +3 -0
  82. package/esm/oai.d.ts +0 -5
  83. package/esm/oai.d.ts.map +0 -1
  84. package/esm/oai.js +0 -2
  85. package/esm/oai.js.map +0 -1
  86. package/esm/types/Ref.d.ts +0 -4
  87. package/esm/types/Ref.d.ts.map +0 -1
  88. package/esm/types/Ref.js +0 -14
  89. package/esm/types/Ref.js.map +0 -1
  90. package/esm/types/RootTy.d.ts +0 -8
  91. package/esm/types/RootTy.d.ts.map +0 -1
  92. package/esm/types/RootTy.js +0 -17
  93. package/esm/types/RootTy.js.map +0 -1
  94. package/esm/types/constant.d.ts +0 -3
  95. package/esm/types/constant.d.ts.map +0 -1
  96. package/esm/types/constant.js +0 -7
  97. package/esm/types/constant.js.map +0 -1
  98. package/esm/util/phantoms.d.ts +0 -2
  99. package/esm/util/phantoms.d.ts.map +0 -1
  100. package/esm/util/phantoms.js +0 -4
  101. package/esm/util/phantoms.js.map +0 -1
  102. package/esm/util/recombineTaggedTemplateArgs.d.ts +0 -2
  103. package/esm/util/recombineTaggedTemplateArgs.d.ts.map +0 -1
  104. package/esm/util/recombineTaggedTemplateArgs.js +0 -4
  105. package/esm/util/recombineTaggedTemplateArgs.js.map +0 -1
  106. package/src/oai.ts +0 -5
  107. package/src/types/Ref.ts +0 -19
  108. package/src/types/RootTy.ts +0 -38
  109. package/src/types/constant.ts +0 -7
  110. package/src/util/phantoms.ts +0 -3
  111. package/src/util/recombineTaggedTemplateArgs.ts +0 -6
@@ -0,0 +1,3 @@
1
+ import { Ty } from "./Ty.js";
2
+ export declare function transform<T, P extends keyof any, R extends boolean, I>(ty: Ty<I, P, R>, transform: (value: I) => T): Ty<T, P, R>;
3
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/types/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE5B,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EACpE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACf,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GACzB,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAEb"}
@@ -0,0 +1,5 @@
1
+ import { Ty } from "./Ty.js";
2
+ export function transform(ty, transform) {
3
+ return Ty((ref) => ref(ty), ty[""].root, (value) => transform(value));
4
+ }
5
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/types/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE5B,MAAM,UAAU,SAAS,CACvB,EAAe,EACf,SAA0B;IAE1B,OAAO,EAAE,CAAa,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;AACnF,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Ty } from "./Ty.js";
2
+ export declare function tuple<F extends Ty[]>(...elements: F): Ty<{
3
+ [K in keyof F]: F[K]["T"];
4
+ }, F[number]["P"], true>;
5
+ //# sourceMappingURL=tuple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tuple.d.ts","sourceRoot":"","sources":["../../src/types/tuple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE5B,wBAAgB,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE,EAClC,GAAG,QAAQ,EAAE,CAAC,GACb,EAAE,CAAC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;CAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAYzD"}
@@ -0,0 +1,11 @@
1
+ import { Ty } from "./Ty.js";
2
+ export function tuple(...elements) {
3
+ const { length } = elements;
4
+ return Ty((ref) => ({
5
+ type: "object",
6
+ properties: Object.fromEntries(Array.from({ length }, (_0, i) => [i, ref(elements[i])])),
7
+ additionalProperties: false,
8
+ required: Object.keys(Array.from({ length }, (_0, i) => i)),
9
+ }), true, (v) => Array.from({ length }, (_0, i) => elements[i][""].transform(v[i])));
10
+ }
11
+ //# sourceMappingURL=tuple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tuple.js","sourceRoot":"","sources":["../../src/types/tuple.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAE5B,MAAM,UAAU,KAAK,CACnB,GAAG,QAAW;IAEd,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IAC3B,OAAO,EAAE,CACP,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACR,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;QACzF,oBAAoB,EAAE,KAAK;QAC3B,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;KAC5D,CAAC,EACF,IAAI,EACJ,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAU,CACpF,CAAA;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function recombine(strings: TemplateStringsArray, values: Array<number | string>): string;
2
+ //# sourceMappingURL=recombine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recombine.d.ts","sourceRoot":"","sources":["../../src/util/recombine.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAE/F"}
@@ -0,0 +1,4 @@
1
+ export function recombine(strings, values) {
2
+ return strings.reduce((acc, cur, i) => `${acc}${cur}${values[i] ?? ""}`, "");
3
+ }
4
+ //# sourceMappingURL=recombine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recombine.js","sourceRoot":"","sources":["../../src/util/recombine.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,OAA6B,EAAE,MAA8B;IACrF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AAC9E,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "structured-outputs",
3
- "version": "0.1.0-beta.22",
3
+ "version": "0.1.0-beta.23",
4
4
  "description": "A library for working with OpenAI's structured outputs.",
5
5
  "repository": "github:harrysolovay/structured-outputs.git",
6
6
  "license": "Apache-2.0",
@@ -1,25 +1,23 @@
1
- import type { ChatCompletion, ChatCompletionChoice, JsonSchema } from "./oai.js"
2
- import type { RootTy } from "./types/mod.js"
3
- import { recombineTaggedTemplateArgs } from "./util/recombineTaggedTemplateArgs.js"
1
+ import type Openai from "openai"
2
+ import type { Ty } from "./types/mod.js"
3
+ import { recombine } from "./util/recombine.js"
4
4
 
5
5
  export interface ResponseFormat<T> {
6
6
  (template: TemplateStringsArray, ...quasis: Array<string>): ResponseFormat<T>
7
7
  type: "json_schema"
8
8
  /** The desired return type in JSON Schema. */
9
- json_schema: JsonSchema
10
- /** Parse the content of the first choice into a typed object. */
11
- parseFirstChoice(completion: ChatCompletion): T
12
- /** Parse all choice contents into an array of typed object. */
13
- parseChoices(completion: ChatCompletion): Array<T>
9
+ json_schema: Openai.ResponseFormatJSONSchema["json_schema"]
10
+ /** Transform the content of the first choice into a typed object. */
11
+ into(completion: ChatCompletion): T
14
12
  }
15
13
 
16
- export function ResponseFormat<T>(name: string, ty: RootTy<T, never>): ResponseFormat<T> {
14
+ export function ResponseFormat<T>(name: string, ty: Ty<T, never, true>): ResponseFormat<T> {
17
15
  return ResponseFormat_(name, ty)
18
16
  }
19
17
 
20
18
  function ResponseFormat_<T>(
21
19
  name: string,
22
- ty: RootTy<T, never>,
20
+ ty: Ty<T, never>,
23
21
  description?: string,
24
22
  ): ResponseFormat<T> {
25
23
  return Object.assign(
@@ -27,7 +25,7 @@ function ResponseFormat_<T>(
27
25
  ResponseFormat_(
28
26
  name,
29
27
  ty,
30
- description ? `${description} ${recombineTaggedTemplateArgs(template, quasis)}` : undefined,
28
+ description ? `${description} ${recombine(template, quasis)}` : undefined,
31
29
  ),
32
30
  {
33
31
  type: "json_schema" as const,
@@ -37,11 +35,8 @@ function ResponseFormat_<T>(
37
35
  schema: ty.schema(),
38
36
  strict: true,
39
37
  },
40
- parseFirstChoice: (completion: ChatCompletion): T => {
41
- return JSON.parse(ResponseFormat.unwrapFirstChoice(completion))
42
- },
43
- parseChoices: (completion: ChatCompletion): Array<T> => {
44
- return ResponseFormat.unwrapChoices(completion).map((content) => JSON.parse(content))
38
+ into: (completion: ChatCompletion): T => {
39
+ return ty[""].transform(JSON.parse(ResponseFormat.unwrapFirstChoice(completion)))
45
40
  },
46
41
  toJSON() {
47
42
  const { type, json_schema } = this
@@ -64,7 +59,7 @@ export namespace ResponseFormat {
64
59
  return completions.choices.map(unwrapChoice)
65
60
  }
66
61
 
67
- function unwrapChoice(choice: ChatCompletionChoice) {
62
+ function unwrapChoice(choice: Openai.Chat.Completions.ChatCompletion.Choice) {
68
63
  const { finish_reason, message } = choice
69
64
  if (finish_reason !== "stop") {
70
65
  throw new ResponseFormatUnwrapError(
@@ -87,3 +82,5 @@ export namespace ResponseFormat {
87
82
  export class ResponseFormatUnwrapError extends Error {
88
83
  override readonly name = "UnwrapResponseError"
89
84
  }
85
+
86
+ type ChatCompletion = Openai.Chat.ChatCompletion
package/src/Tool.ts CHANGED
@@ -1,18 +1,17 @@
1
- import type { RootTy, Schema } from "./types/mod.js"
2
- import { recombineTaggedTemplateArgs } from "./util/recombineTaggedTemplateArgs.js"
1
+ import type { Schema, Ty } from "./types/mod.js"
2
+ import { recombine } from "./util/recombine.js"
3
3
 
4
- /** @experimental */
5
- export function Tool<T>(name: string, ty: RootTy<T, never>): Tool<T> {
4
+ export function Tool<T>(name: string, ty: Ty<T, never, true>): Tool<T> {
6
5
  return Tool_(name, ty)
7
6
  }
8
7
 
9
- function Tool_<T>(name: string, ty: RootTy<T, never>, description?: string): Tool<T> {
8
+ function Tool_<T>(name: string, ty: Ty<T, never, true>, description?: string): Tool<T> {
10
9
  return Object.assign(
11
10
  (template: TemplateStringsArray, ...quasis: Array<string>) =>
12
11
  Tool_(
13
12
  name,
14
13
  ty,
15
- description ? `${description} ${recombineTaggedTemplateArgs(template, quasis)}` : undefined,
14
+ description ? `${description} ${recombine(template, quasis)}` : undefined,
16
15
  ),
17
16
  {
18
17
  type: "function" as const,
package/src/types/Ty.ts CHANGED
@@ -1,50 +1,91 @@
1
- import { phantoms } from "../util/phantoms.js"
2
- import type { Ref } from "./Ref.js"
3
- import type { RootTy } from "./RootTy.js"
1
+ import { recombine } from "../util/recombine.js"
4
2
 
5
- export function Ty<T, P extends keyof any = never>(
6
- toSchema: ToSchema,
3
+ export interface Ty<T = any, P extends keyof any = keyof any, R extends boolean = boolean> {
4
+ <P2 extends Array<keyof any>>(
5
+ template: TemplateStringsArray,
6
+ ...placeheld: P2
7
+ ): Ty<T, P | P2[number], R>
8
+
9
+ /** The native TypeScript type. The runtime value is nonexistent. */
10
+ T: T
11
+ /** The literal types of the placeheld keys. The runtime value is nonexistent. */
12
+ P: P
13
+
14
+ "": {
15
+ subschema: Subschema
16
+ root: R
17
+ transform: (value: any) => any
18
+ context: Array<Context>
19
+ applied: Applied
20
+ }
21
+
22
+ /** Inject context into that which is placeheld. */
23
+ fill: <A extends Partial<Record<P, number | string>>>(
24
+ values: A,
25
+ ) => Ty<T, Exclude<P, keyof A>, R>
26
+
27
+ /** Get the corresponding JSON Schema. */
28
+ schema(this: Ty<T, never>): Schema
29
+ }
30
+
31
+ export function Ty<T, P extends keyof any, R extends boolean, I = T>(
32
+ subschema: Subschema,
33
+ root: R,
34
+ transform: (value: I) => T = (value) => value as never,
7
35
  context: Array<Context> = [],
8
36
  applied: Applied = {},
9
- ): Ty<T, P> {
37
+ ): Ty<T, P, R> {
10
38
  return Object.assign(
11
39
  <P2 extends Array<keyof any>>(template: TemplateStringsArray, ...placeheld: P2) =>
12
- Ty<T, P | P2[number]>(toSchema, [{ template, placeheld }, ...context], applied),
13
- phantoms<{ T: T; P: P }>(),
40
+ Ty<T, P | P2[number], R, I>(
41
+ subschema,
42
+ root,
43
+ transform,
44
+ [{ template, placeheld }, ...context],
45
+ applied,
46
+ ),
47
+ {} as { T: T; P: P },
14
48
  {
15
- "": { toSchema, context, applied },
49
+ "": {
50
+ subschema,
51
+ root,
52
+ transform,
53
+ context,
54
+ applied,
55
+ },
16
56
  fill: <A extends Partial<Record<P, string | number>>>(values: A) => {
17
- return Ty<T, Exclude<P, keyof A>>(toSchema, context, { ...applied, ...values })
57
+ return Ty<T, Exclude<P, keyof A>, R, I>(subschema, root, transform, context, {
58
+ ...applied,
59
+ ...values,
60
+ })
18
61
  },
19
- isRoot(): this is RootTy {
20
- return false
62
+ schema(this: Ty<T, never>) {
63
+ return SubschemaFactory({})(this)
21
64
  },
22
65
  },
23
66
  )
24
67
  }
25
68
 
26
- export interface Ty<T = any, P extends keyof any = keyof any> {
27
- <P2 extends Array<keyof any>>(
28
- template: TemplateStringsArray,
29
- ...placeheld: P2
30
- ): Ty<T, P | P2[number]>
31
- T: T
32
- P: P
33
- "": {
34
- toSchema: ToSchema
35
- context: Array<Context>
36
- applied: Applied
69
+ export type Subschema = (subschema: SubschemaFactory) => Schema
70
+
71
+ export type SubschemaFactory = (ty: Ty) => Schema
72
+ export function SubschemaFactory(applied: Applied): SubschemaFactory {
73
+ return (ty) => {
74
+ applied = { ...applied, ...ty[""].applied }
75
+ const description = ty[""].context
76
+ .map(({ template, placeheld }) => recombine(template, placeheld.map((k) => applied[k]!)))
77
+ .join(" ")
78
+ return {
79
+ ...ty[""].subschema(SubschemaFactory(applied)),
80
+ ...description ? { description } : {},
81
+ }
37
82
  }
38
- fill: <A extends Partial<Record<P, number | string>>>(values: A) => Ty<T, Exclude<P, keyof A>>
39
- isRoot(): this is RootTy
40
83
  }
41
84
 
42
- export type ToSchema = (ref: Ref) => Schema
43
- export type Schema = Record<string, unknown>
44
-
45
- export interface Context {
85
+ interface Context {
46
86
  template: TemplateStringsArray
47
87
  placeheld: Array<keyof any>
48
88
  }
89
+ type Applied = Record<keyof any, number | string>
49
90
 
50
- export type Applied = Record<keyof any, number | string>
91
+ export type Schema = Record<string, unknown>
@@ -1,8 +1,12 @@
1
1
  import { Ty } from "./Ty.js"
2
2
 
3
- export function array<E extends Ty>(element: E): Ty<Array<E["T"]>, E["P"]> {
4
- return Ty((ref) => ({
5
- type: "array",
6
- items: ref(element),
7
- }))
3
+ export function array<E extends Ty>(element: E): Ty<Array<E["T"]>, E["P"], false> {
4
+ return Ty(
5
+ (ref) => ({
6
+ type: "array",
7
+ items: ref(element),
8
+ }),
9
+ false,
10
+ (value) => value.map(element[""].transform),
11
+ )
8
12
  }
@@ -3,7 +3,7 @@ import { Ty } from "./Ty.js"
3
3
 
4
4
  export function constantUnion<M extends Array<number | string>>(
5
5
  ...members: M
6
- ): Ty<M[number], never> {
6
+ ): Ty<M[number], never, false> {
7
7
  const [strings, numbers] = partition(members, (v) => typeof v === "string")
8
8
  return Ty(() => ({
9
9
  anyOf: [
@@ -20,5 +20,5 @@ export function constantUnion<M extends Array<number | string>>(
20
20
  }]
21
21
  : [],
22
22
  ],
23
- }))
23
+ }), false)
24
24
  }
package/src/types/mod.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  export * from "./array.js"
2
- export * from "./constant.js"
3
2
  export * from "./constantUnion.js"
4
3
  export * from "./object.js"
5
4
  export * from "./primitives.js"
6
- export * from "./Ref.js"
7
- export * from "./RootTy.js"
8
5
  export * from "./std/mod.js"
9
6
  export * from "./taggedUnion.js"
7
+ export * from "./transform.js"
8
+ export * from "./tuple.js"
10
9
  export * from "./Ty.js"
@@ -1,13 +1,19 @@
1
- import { RootTy } from "./RootTy.js"
2
- import type { Ty } from "./Ty.js"
1
+ import { Ty } from "./Ty.js"
3
2
 
4
3
  export function object<F extends Record<string, Ty>>(
5
4
  fields: F,
6
- ): RootTy<{ [K in keyof F]: F[K]["T"] }, F[keyof F]["P"]> {
7
- return RootTy((ref) => ({
8
- type: "object",
9
- properties: Object.fromEntries(Object.entries(fields).map(([k, v]) => [k, ref(v)])),
10
- additionalProperties: false,
11
- required: Object.keys(fields),
12
- }))
5
+ ): Ty<{ [K in keyof F]: F[K]["T"] }, F[keyof F]["P"], true> {
6
+ return Ty(
7
+ (ref) => ({
8
+ type: "object",
9
+ properties: Object.fromEntries(Object.entries(fields).map(([k, v]) => [k, ref(v)])),
10
+ additionalProperties: false,
11
+ required: Object.keys(fields),
12
+ }),
13
+ true,
14
+ (v) =>
15
+ Object.fromEntries(
16
+ Object.entries(v).map(([k, v]) => [k, fields[k]![""].transform(v)]),
17
+ ) as never,
18
+ )
13
19
  }
@@ -1,17 +1,17 @@
1
1
  import { Ty } from "./Ty.js"
2
2
 
3
- export const none: Ty<null, never> = Ty(() => ({
3
+ export const none: Ty<null, never, false> = Ty(() => ({
4
4
  type: "null",
5
- }))
5
+ }), false)
6
6
 
7
- export const boolean: Ty<boolean, never> = Ty(() => ({
7
+ export const boolean: Ty<boolean, never, false> = Ty(() => ({
8
8
  type: "boolean",
9
- }))
9
+ }), false)
10
10
 
11
- export const number: Ty<number, never> = Ty(() => ({
11
+ export const number: Ty<number, never, false> = Ty(() => ({
12
12
  type: "number",
13
- }))
13
+ }), false)
14
14
 
15
- export const string: Ty<string, never> = Ty(() => ({
15
+ export const string: Ty<string, never, false> = Ty(() => ({
16
16
  type: "string",
17
- }))
17
+ }), false)
@@ -0,0 +1,19 @@
1
+ import { object } from "../object.js"
2
+ import { number } from "../primitives.js"
3
+ import { transform } from "../transform.js"
4
+ import type { Ty } from "../Ty.js"
5
+
6
+ export { Date_ as Date }
7
+ const Date_: Ty<Date, never, true> = transform(
8
+ object({
9
+ year: number,
10
+ month: number`Zero-based (0 for January, 11 for December).`,
11
+ day: number`Day of the month (1-31). Ensure within available range for the specified month.`,
12
+ hour: number`Zero-based (0-23)`,
13
+ minute: number`Zero-based (0-59)`,
14
+ second: number`Zero-based (0-59)`,
15
+ millisecond: number`Zero-based (0-999)`,
16
+ }),
17
+ ({ year, month, day, hour, minute, second, millisecond }) =>
18
+ new Date(year, month, day, hour, minute, second, millisecond),
19
+ )
@@ -2,10 +2,10 @@ import { none } from "../primitives.js"
2
2
  import { taggedUnion } from "../taggedUnion.js"
3
3
  import type { Ty } from "../Ty.js"
4
4
 
5
- export function option<S extends Ty>(Some: S): ReturnType<
5
+ export function Option<S extends Ty>(Some: S): ReturnType<
6
6
  typeof taggedUnion<{
7
7
  Some: S
8
- None: Ty<null, never>
8
+ None: typeof none
9
9
  }>
10
10
  > {
11
11
  return taggedUnion({
@@ -0,0 +1,27 @@
1
+ import { object } from "../object.js"
2
+ import { number } from "../primitives.js"
3
+ import { transform } from "../transform.js"
4
+ import type { Ty } from "../Ty.js"
5
+
6
+ export const Rgb: Ty<
7
+ {
8
+ r: number
9
+ g: number
10
+ b: number
11
+ },
12
+ never,
13
+ true
14
+ > = object({
15
+ r: number`Between 0 and 255`,
16
+ g: number`Between 0 and 255`,
17
+ b: number`Between 0 and 255`,
18
+ })
19
+
20
+ export const Hex: Ty<string, never, true> = transform(
21
+ Rgb,
22
+ ({ r, g, b }) => `${toHex(r)}${toHex(g)}${toHex(b)}"`,
23
+ )
24
+
25
+ function toHex(value: number): string {
26
+ return value.toString(16).padStart(2, "0")
27
+ }
@@ -1,2 +1,4 @@
1
+ export * from "./color.js"
2
+ export * from "./Date.js"
1
3
  export * from "./Option.js"
2
4
  export * from "./Wrapper.js"
@@ -1,4 +1,4 @@
1
- import { Ty } from "./Ty.js"
1
+ import { type Schema, Ty } from "./Ty.js"
2
2
 
3
3
  export function taggedUnion<M extends Record<string, Ty>>(members: M): Ty<
4
4
  {
@@ -7,21 +7,34 @@ export function taggedUnion<M extends Record<string, Ty>>(members: M): Ty<
7
7
  value: M[K]["T"]
8
8
  }
9
9
  }[keyof M],
10
- M[keyof M]["P"]
10
+ M[keyof M]["P"],
11
+ false
11
12
  > {
12
- return Ty((ref) => ({
13
- discriminator: "type",
14
- anyOf: Object.entries(members).map(([k, v]) => ({
15
- type: "object",
16
- properties: {
17
- type: {
18
- type: "string",
19
- const: k,
13
+ const entries = Object.entries(members)
14
+ return Ty(
15
+ (subschema) =>
16
+ entries.length === 1
17
+ ? variant(entries[0]![0], subschema(entries[0]![1]))
18
+ : {
19
+ discriminator: "type",
20
+ anyOf: entries.map(([k, v]) => variant(k, subschema(v))),
20
21
  },
21
- value: ref(v),
22
+ false,
23
+ (v) => members[v.type]![""].transform(v),
24
+ )
25
+ }
26
+
27
+ function variant(type: string, value: Schema) {
28
+ return {
29
+ type: "object",
30
+ properties: {
31
+ type: {
32
+ type: "string",
33
+ const: type,
22
34
  },
23
- required: ["type", "value"],
24
- additionalProperties: false,
25
- })),
26
- }))
35
+ value,
36
+ },
37
+ required: ["type", "value"],
38
+ additionalProperties: false,
39
+ }
27
40
  }
@@ -0,0 +1,8 @@
1
+ import { Ty } from "./Ty.js"
2
+
3
+ export function transform<T, P extends keyof any, R extends boolean, I>(
4
+ ty: Ty<I, P, R>,
5
+ transform: (value: I) => T,
6
+ ): Ty<T, P, R> {
7
+ return Ty<T, P, R, I>((ref) => ref(ty), ty[""].root, (value) => transform(value))
8
+ }
@@ -0,0 +1,17 @@
1
+ import { Ty } from "./Ty.js"
2
+
3
+ export function tuple<F extends Ty[]>(
4
+ ...elements: F
5
+ ): Ty<{ [K in keyof F]: F[K]["T"] }, F[number]["P"], true> {
6
+ const { length } = elements
7
+ return Ty(
8
+ (ref) => ({
9
+ type: "object",
10
+ properties: Object.fromEntries(Array.from({ length }, (_0, i) => [i, ref(elements[i]!)])),
11
+ additionalProperties: false,
12
+ required: Object.keys(Array.from({ length }, (_0, i) => i)),
13
+ }),
14
+ true,
15
+ (v) => Array.from({ length }, (_0, i) => elements[i]![""].transform(v[i])) as never,
16
+ )
17
+ }
@@ -0,0 +1,3 @@
1
+ export function recombine(strings: TemplateStringsArray, values: Array<number | string>): string {
2
+ return strings.reduce((acc, cur, i) => `${acc}${cur}${values[i] ?? ""}`, "")
3
+ }
package/esm/oai.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import type Openai from "openai";
2
- export type JsonSchema = Openai.ResponseFormatJSONSchema["json_schema"];
3
- export type ChatCompletion = Openai.Chat.ChatCompletion;
4
- export type ChatCompletionChoice = Openai.Chat.Completions.ChatCompletion.Choice;
5
- //# sourceMappingURL=oai.d.ts.map
package/esm/oai.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"oai.d.ts","sourceRoot":"","sources":["../src/oai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAEhC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAA;AACvE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAA;AACvD,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,MAAM,CAAA"}
package/esm/oai.js DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=oai.js.map
package/esm/oai.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"oai.js","sourceRoot":"","sources":["../src/oai.ts"],"names":[],"mappings":""}
@@ -1,4 +0,0 @@
1
- import type { Applied, Schema, Ty } from "./Ty.js";
2
- export type Ref = (ty: Ty) => Schema;
3
- export declare function Ref(applied: Applied): Ref;
4
- //# sourceMappingURL=Ref.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Ref.d.ts","sourceRoot":"","sources":["../../src/types/Ref.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAElD,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,MAAM,CAAA;AAEpC,wBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG,CAazC"}
package/esm/types/Ref.js DELETED
@@ -1,14 +0,0 @@
1
- import { recombineTaggedTemplateArgs } from "../util/recombineTaggedTemplateArgs.js";
2
- export function Ref(applied) {
3
- return (ty) => {
4
- applied = { ...applied, ...ty[""].applied };
5
- const description = ty[""].context
6
- .map(({ template, placeheld }) => recombineTaggedTemplateArgs(template, placeheld.map((k) => applied[k])))
7
- .join(" ");
8
- return {
9
- ...ty[""].toSchema(Ref(applied)),
10
- ...description ? { description } : {},
11
- };
12
- };
13
- }
14
- //# sourceMappingURL=Ref.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Ref.js","sourceRoot":"","sources":["../../src/types/Ref.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAA;AAKpF,MAAM,UAAU,GAAG,CAAC,OAAgB;IAClC,OAAO,CAAC,EAAE,EAAE,EAAE;QACZ,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;QAC3C,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAO;aAC/B,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAC/B,2BAA2B,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC,CACzE;aACA,IAAI,CAAC,GAAG,CAAC,CAAA;QACZ,OAAO;YACL,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAChC,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;SACtC,CAAA;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { Applied, Context, Schema, ToSchema, Ty } from "./Ty.js";
2
- export declare function RootTy<T, P extends keyof any = never>(toSchema: ToSchema, context?: Array<Context>, applied?: Applied): RootTy<T, P>;
3
- export interface RootTy<T = any, P extends keyof any = keyof any> extends Ty<T, P> {
4
- <P2 extends Array<keyof any>>(template: TemplateStringsArray, ...placeheld: P2): RootTy<T, P | P2[number]>;
5
- fill: <A extends Partial<Record<P, number | string>>>(values: A) => RootTy<T, Exclude<P, keyof A>>;
6
- schema(this: RootTy<T, never>): Schema;
7
- }
8
- //# sourceMappingURL=RootTy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RootTy.d.ts","sourceRoot":"","sources":["../../src/types/RootTy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAErE,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,GAAG,KAAK,EACnD,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,KAAK,CAAC,OAAO,CAAM,EAC5B,OAAO,GAAE,OAAY,GACpB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAkBd;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,GAAG,MAAM,GAAG,CAAE,SAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC,EAAE,SAAS,KAAK,CAAC,MAAM,GAAG,CAAC,EAC1B,QAAQ,EAAE,oBAAoB,EAC9B,GAAG,SAAS,EAAE,EAAE,GACf,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAClD,MAAM,EAAE,CAAC,KACN,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IACnC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,CAAA;CACvC"}
@@ -1,17 +0,0 @@
1
- import { phantoms } from "../util/phantoms.js";
2
- import { Ref } from "./Ref.js";
3
- export function RootTy(toSchema, context = [], applied = {}) {
4
- return Object.assign((template, ...placeheld) => RootTy(toSchema, [{ template, placeheld }, ...context], applied), phantoms(), {
5
- "": { toSchema, context, applied },
6
- fill: (values) => {
7
- return RootTy(toSchema, context, { ...applied, ...values });
8
- },
9
- schema() {
10
- return Ref({})(this);
11
- },
12
- isRoot() {
13
- return true;
14
- },
15
- });
16
- }
17
- //# sourceMappingURL=RootTy.js.map