shapecraft 1.0.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.
Files changed (112) hide show
  1. package/CLAUDE.md +227 -0
  2. package/README.md +22 -0
  3. package/apps/cli/node_modules/.bin/prettier +21 -0
  4. package/apps/cli/node_modules/.bin/tsc +21 -0
  5. package/apps/cli/node_modules/.bin/tsserver +21 -0
  6. package/apps/cli/node_modules/.bin/tsx +21 -0
  7. package/apps/cli/node_modules/.bin/vitest +21 -0
  8. package/apps/cli/package.json +47 -0
  9. package/apps/cli/src/index.ts +98 -0
  10. package/apps/cli/tsconfig.cjs.json +10 -0
  11. package/apps/cli/tsconfig.esm.json +10 -0
  12. package/apps/cli/tsconfig.json +22 -0
  13. package/package.json +16 -0
  14. package/packages/core/node_modules/.bin/prettier +21 -0
  15. package/packages/core/node_modules/.bin/tsc +21 -0
  16. package/packages/core/node_modules/.bin/tsserver +21 -0
  17. package/packages/core/node_modules/.bin/tsx +21 -0
  18. package/packages/core/node_modules/.bin/vitest +21 -0
  19. package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  20. package/packages/core/package.json +44 -0
  21. package/packages/core/src/common/array.test.ts +19 -0
  22. package/packages/core/src/common/array.ts +15 -0
  23. package/packages/core/src/common/index.ts +5 -0
  24. package/packages/core/src/common/is.ts +23 -0
  25. package/packages/core/src/common/object.ts +35 -0
  26. package/packages/core/src/common/phantom.ts +1 -0
  27. package/packages/core/src/common/result.ts +43 -0
  28. package/packages/core/src/common/string.ts +28 -0
  29. package/packages/core/src/common/types.ts +34 -0
  30. package/packages/core/src/index.ts +1 -0
  31. package/packages/core/src/shape/annotate.ts +139 -0
  32. package/packages/core/src/shape/annotation.ts +47 -0
  33. package/packages/core/src/shape/base.ts +71 -0
  34. package/packages/core/src/shape/builder.test.ts +728 -0
  35. package/packages/core/src/shape/builder.ts +475 -0
  36. package/packages/core/src/shape/error.ts +4 -0
  37. package/packages/core/src/shape/index.ts +3 -0
  38. package/packages/core/src/shape/number.ts +118 -0
  39. package/packages/core/src/shape/shape.test.ts +792 -0
  40. package/packages/core/src/shape/shape.ts +377 -0
  41. package/packages/core/src/shape/tags.ts +14 -0
  42. package/packages/core/src/shape/transforms/index.ts +3 -0
  43. package/packages/core/src/shape/transforms/json-schema/index.ts +2 -0
  44. package/packages/core/src/shape/transforms/json-schema/transform.test.ts +850 -0
  45. package/packages/core/src/shape/transforms/json-schema/transform.ts +882 -0
  46. package/packages/core/src/shape/transforms/json-schema/types.ts +132 -0
  47. package/packages/core/src/shape/transforms/sql/dialects/dialect.ts +89 -0
  48. package/packages/core/src/shape/transforms/sql/dialects/index.ts +14 -0
  49. package/packages/core/src/shape/transforms/sql/dialects/postgres.ts +392 -0
  50. package/packages/core/src/shape/transforms/sql/dialects/sqlite.ts +333 -0
  51. package/packages/core/src/shape/transforms/sql/from-sql.test.ts +704 -0
  52. package/packages/core/src/shape/transforms/sql/from-sql.ts +210 -0
  53. package/packages/core/src/shape/transforms/sql/index.ts +3 -0
  54. package/packages/core/src/shape/transforms/sql/options.ts +6 -0
  55. package/packages/core/src/shape/transforms/sql/parser/check-decoder.ts +457 -0
  56. package/packages/core/src/shape/transforms/sql/parser/create-domain.ts +105 -0
  57. package/packages/core/src/shape/transforms/sql/parser/create-table.ts +809 -0
  58. package/packages/core/src/shape/transforms/sql/parser/create-type.ts +91 -0
  59. package/packages/core/src/shape/transforms/sql/parser/cursor.ts +179 -0
  60. package/packages/core/src/shape/transforms/sql/parser/default-decoder.ts +129 -0
  61. package/packages/core/src/shape/transforms/sql/parser/lexer.ts +289 -0
  62. package/packages/core/src/shape/transforms/sql/parser/pg-types.ts +247 -0
  63. package/packages/core/src/shape/transforms/sql/parser/sqlite-types.ts +103 -0
  64. package/packages/core/src/shape/transforms/sql/parser/statements.ts +127 -0
  65. package/packages/core/src/shape/transforms/sql/parser/type-spec.ts +159 -0
  66. package/packages/core/src/shape/transforms/sql/transform.sqlite.test.ts +448 -0
  67. package/packages/core/src/shape/transforms/sql/transform.test.ts +880 -0
  68. package/packages/core/src/shape/transforms/sql/transform.ts +295 -0
  69. package/packages/core/src/shape/transforms/typescript/index.ts +1 -0
  70. package/packages/core/src/shape/transforms/typescript/transform.ts +211 -0
  71. package/packages/core/src/shape/tuple.test.ts +171 -0
  72. package/packages/core/src/shape/validate.ts +413 -0
  73. package/packages/core/tsconfig.cjs.json +11 -0
  74. package/packages/core/tsconfig.esm.json +10 -0
  75. package/packages/core/tsconfig.json +23 -0
  76. package/packages/samples/node_modules/.bin/prettier +21 -0
  77. package/packages/samples/node_modules/.bin/tsc +21 -0
  78. package/packages/samples/node_modules/.bin/tsserver +21 -0
  79. package/packages/samples/node_modules/.bin/tsx +21 -0
  80. package/packages/samples/node_modules/.bin/vitest +21 -0
  81. package/packages/samples/package.json +47 -0
  82. package/packages/samples/src/blog.ts +49 -0
  83. package/packages/samples/src/config.ts +50 -0
  84. package/packages/samples/src/ecommerce.ts +65 -0
  85. package/packages/samples/src/embeddings.ts +43 -0
  86. package/packages/samples/src/events.ts +52 -0
  87. package/packages/samples/src/geometry.ts +62 -0
  88. package/packages/samples/src/index.ts +9 -0
  89. package/packages/samples/src/relational.ts +17 -0
  90. package/packages/samples/src/tuples.ts +67 -0
  91. package/packages/samples/src/user.ts +9 -0
  92. package/packages/samples/tsconfig.cjs.json +11 -0
  93. package/packages/samples/tsconfig.esm.json +10 -0
  94. package/packages/samples/tsconfig.json +23 -0
  95. package/pnpm-workspace.yaml +3 -0
  96. package/test-data/json-schema/address.json +35 -0
  97. package/test-data/json-schema/array-of-things.json +36 -0
  98. package/test-data/json-schema/basic.json +21 -0
  99. package/test-data/json-schema/blog-post.json +29 -0
  100. package/test-data/json-schema/calendar.json +48 -0
  101. package/test-data/json-schema/complex-object-with-nested-properties.json +41 -0
  102. package/test-data/json-schema/ecommerce-complex.json +344 -0
  103. package/test-data/json-schema/ecommerce-system.json +27 -0
  104. package/test-data/json-schema/enumerated-values.json +11 -0
  105. package/test-data/json-schema/fstab-entry.json +92 -0
  106. package/test-data/json-schema/geographical-location.json +20 -0
  107. package/test-data/json-schema/health-record.json +41 -0
  108. package/test-data/json-schema/job-posting.json +33 -0
  109. package/test-data/json-schema/movie.json +35 -0
  110. package/test-data/json-schema/regular-expression-pattern.json +12 -0
  111. package/test-data/json-schema/user-profile.json +33 -0
  112. package/test-data/sql/ecommerce.sql +641 -0
@@ -0,0 +1,377 @@
1
+ import { forceString, isPlainObject, uniqueBy } from "../common";
2
+ import { remapObjectValues } from "../common/object";
3
+ import { Arrayish, Binary, Prettify } from "../common/types";
4
+ import { AnnotatedLoose, Annotation } from "./annotation";
5
+ import {
6
+ _WithPhantom,
7
+ createBaseWithInput as bwi,
8
+ createBaseWithPhantom as bwp,
9
+ ShapeBase,
10
+ ShapeLoose,
11
+ } from "./base";
12
+ import {
13
+ inferNumberTag,
14
+ inferNumberTagFromSamples,
15
+ } from "./number";
16
+ import { NumberTag } from "./tags";
17
+ import * as _validate from "./validate";
18
+
19
+ export namespace shapes {
20
+ ///////////////////////////////////// types ///////////////////////////////////////////////
21
+
22
+ // ---------- primitives
23
+ export interface ShapeNumber<
24
+ Input extends number | null = number | null,
25
+ Tag extends NumberTag = NumberTag,
26
+ > extends ShapeBase<
27
+ "number",
28
+ Input,
29
+ [Input] extends [number] ? Input : number
30
+ > {
31
+ tag: Tag;
32
+ literal?: boolean;
33
+ }
34
+
35
+ export interface ShapeString<
36
+ Input extends string | null = string | null,
37
+ > extends ShapeBase<
38
+ "string",
39
+ Input,
40
+ [Input] extends [string] ? Input : string
41
+ > {
42
+ literal?: boolean;
43
+ }
44
+
45
+ export interface ShapeBoolean<
46
+ Input extends boolean | null = boolean | null,
47
+ > extends ShapeBase<
48
+ "boolean",
49
+ Input,
50
+ [Input] extends [boolean] ? Input : boolean
51
+ > {
52
+ literal?: boolean;
53
+ }
54
+
55
+ export interface ShapeUndefined extends ShapeBase<
56
+ "undefined",
57
+ null,
58
+ undefined
59
+ > {}
60
+ export interface ShapeDate extends ShapeBase<"date", null, Date> {}
61
+ export interface ShapeNil extends ShapeBase<"nil", null, null> {}
62
+ export interface ShapeUnknown extends ShapeBase<"unknown", null, unknown> {}
63
+
64
+ // ---------- collections
65
+ export interface ShapeArray<Item extends Shape = Shape> extends ShapeBase<
66
+ "array",
67
+ Item,
68
+ Array<InferShapeOut<Item>>
69
+ > {}
70
+
71
+ export interface ShapeMapping<
72
+ Rec extends { [key: string]: Shape } = { [key: string]: Shape },
73
+ > extends ShapeBase<"mapping", Rec, Record<string, Shape>> {
74
+ input: Rec;
75
+ _: {
76
+ output: Prettify<
77
+ {
78
+ -readonly [P in keyof Rec as [IsOptional<Rec[P]>] extends [true] ?
79
+ never
80
+ : P]: InferShapeOut<Rec[P]>;
81
+ } & {
82
+ -readonly [P in keyof Rec as [IsOptional<Rec[P]>] extends [true] ? P
83
+ : never]?: InferShapeOut<Rec[P]>;
84
+ }
85
+ >;
86
+ };
87
+ }
88
+
89
+ export interface ShapeRecord<
90
+ KV extends [ShapeKeyable, Shape] = [ShapeKeyable, Shape],
91
+ > extends ShapeBase<
92
+ "record",
93
+ KV,
94
+ Record<InferShapeOut<KV[0]>, InferShapeOut<KV[1]>>
95
+ > {}
96
+
97
+ export interface ShapeVector<
98
+ Dims extends number = number,
99
+ Format extends ShapeNumber = ShapeNumber,
100
+ > extends ShapeBase<
101
+ "vector",
102
+ { dims: Dims; format: Format },
103
+ Array<InferShapeOut<Format>>
104
+ > {}
105
+
106
+ export interface ShapeTuple<
107
+ Of extends readonly Shape[] = readonly Shape[],
108
+ > extends ShapeBase<
109
+ "tuple",
110
+ Of,
111
+ { -readonly [K in keyof Of]: InferShapeOut<Of[K]> }
112
+ > {}
113
+
114
+ export interface ShapeBinary extends ShapeBase<"binary", null, Binary> {}
115
+
116
+ export interface ShapeRange<Item extends Shape = Shape> extends ShapeBase<
117
+ "range",
118
+ Item,
119
+ {
120
+ lower: InferShapeOut<Item> | null;
121
+ upper: InferShapeOut<Item> | null;
122
+ lowerInclusive: boolean;
123
+ upperInclusive: boolean;
124
+ }
125
+ > {}
126
+
127
+ export interface ShapeUnion<
128
+ Of extends Arrayish<Shape> = Arrayish<Shape>,
129
+ > extends ShapeBase<"union", Of, InferShapeOut<Of[`${number}`]>> {}
130
+
131
+ export interface ShapeModule<
132
+ Rec extends Record<string, ShapeMapping> = Record<string, ShapeMapping>,
133
+ > extends ShapeBase<"module", Rec, Record<string, unknown>> {
134
+ input: Rec;
135
+ _: {
136
+ output: {
137
+ -readonly [P in keyof Rec]: InferShapeOut<Rec[P]>;
138
+ };
139
+ };
140
+ }
141
+
142
+ export type ShapeKeyable = ShapeString | ShapeNumber | ShapeBoolean;
143
+
144
+ export type ShapeWithLength = ShapeString | ShapeNumber | ShapeArray;
145
+
146
+ export type ShapeLiteral =
147
+ | MakeLiteral<ShapeString<string>>
148
+ | MakeLiteral<ShapeNumber<number>>
149
+ | MakeLiteral<ShapeBoolean<boolean>>;
150
+
151
+ export type Shape =
152
+ | ShapeNumber
153
+ | ShapeString
154
+ | ShapeBoolean
155
+ | ShapeUndefined
156
+ | ShapeDate
157
+ | ShapeNil
158
+ | ShapeUnknown
159
+ | ShapeArray
160
+ | ShapeMapping
161
+ | ShapeRecord
162
+ | ShapeVector
163
+ | ShapeTuple
164
+ | ShapeBinary
165
+ | ShapeRange
166
+ | ShapeUnion
167
+ | ShapeModule
168
+ | ShapeLiteral;
169
+
170
+ ///////////////////////////////////// type utilities ////////////////////////////////////////
171
+ export type InferShapeOut<S> =
172
+ [S] extends [_WithPhantom] ? S["_"]["output"] : never;
173
+
174
+ export type InputOfShape<S extends Shape> = S["input"];
175
+
176
+ export type Annotated<
177
+ S extends { anno: Annotation },
178
+ A extends Annotation,
179
+ > = S & {
180
+ anno: S["anno"] & A;
181
+ };
182
+
183
+ export type IsOptional<S> =
184
+ [S] extends [AnnotatedLoose] ?
185
+ [S["anno"]["optional"]] extends [true] ?
186
+ true
187
+ : false
188
+ : false;
189
+
190
+ export type MakeLiteral<S extends { type: string }> = S & { literal: true };
191
+
192
+ ///////////////////////////////////// constructors ////////////////////////////////////////
193
+
194
+ const withNumberTag = <
195
+ const S extends ShapeLoose,
196
+ const Tag extends NumberTag,
197
+ >(
198
+ shape: S,
199
+ tag: Tag,
200
+ ): S & { tag: Tag } => ({
201
+ ...shape,
202
+ tag: tag,
203
+ });
204
+
205
+ export const number = (): ShapeNumber<null, "number"> =>
206
+ withNumberTag(bwp("number"), "number");
207
+ export const int = (): ShapeNumber<null, "int"> =>
208
+ withNumberTag(number(), "int");
209
+ export const int8 = (): ShapeNumber<null, "int8"> =>
210
+ withNumberTag(number(), "int8");
211
+ export const uint8 = (): ShapeNumber<null, "uint8"> =>
212
+ withNumberTag(number(), "uint8");
213
+ export const int16 = (): ShapeNumber<null, "int16"> =>
214
+ withNumberTag(number(), "int16");
215
+ export const uint16 = (): ShapeNumber<null, "uint16"> =>
216
+ withNumberTag(number(), "uint16");
217
+ export const int32 = (): ShapeNumber<null, "int32"> =>
218
+ withNumberTag(number(), "int32");
219
+ export const uint32 = (): ShapeNumber<null, "uint32"> =>
220
+ withNumberTag(number(), "uint32");
221
+ export const int64 = (): ShapeNumber<null, "int64"> =>
222
+ withNumberTag(number(), "int64");
223
+ export const uint64 = (): ShapeNumber<null, "uint64"> =>
224
+ withNumberTag(number(), "uint64");
225
+ export const float = (): ShapeNumber<null, "float"> =>
226
+ withNumberTag(number(), "float");
227
+ export const float32 = (): ShapeNumber<null, "float32"> =>
228
+ withNumberTag(number(), "float32");
229
+ export const float64 = (): ShapeNumber<null, "float64"> =>
230
+ withNumberTag(number(), "float64");
231
+
232
+ export const string = (): ShapeString => bwp("string");
233
+ export const boolean = (): ShapeBoolean => bwp("boolean");
234
+ export const notDefined = (): ShapeUndefined => bwp("undefined");
235
+ export const date = (): ShapeDate => bwp("date");
236
+ export const nil = (): ShapeNil => bwp("nil");
237
+ export const unknown = (): ShapeUnknown => bwp("unknown");
238
+
239
+ export function literal<const Input extends boolean>(
240
+ value: Input,
241
+ ): MakeLiteral<ShapeBoolean<Input>>;
242
+ export function literal<const Input extends number>(
243
+ value: Input,
244
+ ): MakeLiteral<ShapeNumber<Input>>;
245
+ export function literal<const Input extends string>(
246
+ value: Input,
247
+ ): MakeLiteral<ShapeString<Input>>;
248
+ export function literal<const Input extends string | number | boolean>(
249
+ value: Input,
250
+ ): ShapeLiteral;
251
+ export function literal<const Input extends string | number | boolean>(
252
+ value: Input,
253
+ ): ShapeLiteral {
254
+ if (typeof value === "number")
255
+ return { ...number(), input: value, literal: true };
256
+ if (typeof value === "string")
257
+ return { ...string(), input: value, literal: true };
258
+ if (typeof value === "boolean")
259
+ return { ...boolean(), input: value, literal: true };
260
+ throw new Error(`type ${typeof value} cannot be a literal`);
261
+ }
262
+
263
+ export function array<const Item extends Shape>(
264
+ item: Item,
265
+ ): ShapeArray<Item> {
266
+ return bwi("array", item);
267
+ }
268
+
269
+ export function mapping<const Rec extends { [key: string]: Shape }>(
270
+ rec: Rec,
271
+ ): ShapeMapping<Rec> {
272
+ return bwi("mapping", rec);
273
+ }
274
+
275
+ export function record<KV extends [ShapeKeyable, Shape]>(
276
+ ...kv: KV
277
+ ): ShapeRecord<KV> {
278
+ return bwi("record", kv);
279
+ }
280
+
281
+ export function vector<const Dims extends number>(
282
+ dims: Dims,
283
+ ): ShapeVector<Dims, ShapeNumber>;
284
+ export function vector<
285
+ const Dims extends number,
286
+ const Format extends ShapeNumber,
287
+ >(dims: Dims, format: Format): ShapeVector<Dims, Format>;
288
+ export function vector<
289
+ const Dims extends number,
290
+ const Format extends ShapeNumber,
291
+ >(dims: Dims, format?: Format): ShapeVector<Dims, Format | ShapeNumber>;
292
+ export function vector<
293
+ const Dims extends number,
294
+ const Format extends ShapeNumber,
295
+ >(dims: Dims, format?: Format): ShapeVector<Dims, Format | ShapeNumber> {
296
+ return bwi("vector", { dims, format: format || number() });
297
+ }
298
+
299
+ export const binary = (): ShapeBinary => bwp("binary");
300
+
301
+ export function range<const Item extends Shape>(
302
+ item: Item,
303
+ ): ShapeRange<Item> {
304
+ return bwi("range", item);
305
+ }
306
+
307
+ export function tuple<const Of extends readonly Shape[]>(
308
+ ...of: Of
309
+ ): ShapeTuple<Of> {
310
+ return bwi("tuple", of);
311
+ }
312
+
313
+ export function union<const Of extends Array<Shape>>(of: Of): ShapeUnion<Of>;
314
+ export function union<const Of extends Arrayish<Shape>>(
315
+ ...of: Of
316
+ ): ShapeUnion<Of>;
317
+ export function union(...of: [Array<Shape>] | Arrayish<Shape>): ShapeUnion {
318
+ const ofs = of.flat();
319
+ const first = ofs[0];
320
+ const items: Arrayish<Shape> =
321
+ ofs.length === 1 && Array.isArray(first) ?
322
+ first
323
+ : (ofs as Arrayish<Shape>);
324
+ return bwi(
325
+ "union",
326
+ uniqueBy(items, (x) => forceString(x)),
327
+ );
328
+ }
329
+
330
+ export function module<const Rec extends Record<string, ShapeMapping>>(
331
+ rec: Rec,
332
+ ): ShapeModule<Rec> {
333
+ return bwi("module", rec);
334
+ }
335
+
336
+ export type AutoOptions = {
337
+ literalNumbers?: boolean | null | undefined;
338
+ literalStrings?: boolean | null | undefined;
339
+ literalBooleans?: boolean | null | undefined;
340
+ };
341
+ export function auto(input: unknown, options: AutoOptions = {}): Shape {
342
+ if (input === null) return nil();
343
+ if (typeof input === "undefined") return notDefined();
344
+ if (typeof input === "string")
345
+ return options.literalStrings ? literal(input) : string();
346
+ if (typeof input === "number")
347
+ return options.literalNumbers ?
348
+ withNumberTag(literal(input), inferNumberTag(input))
349
+ : withNumberTag(number(), inferNumberTag(input));
350
+ if (typeof input === "boolean")
351
+ return options.literalBooleans ? literal(input) : boolean();
352
+ if (input instanceof Date) return date();
353
+ if (input instanceof Uint8Array) return binary();
354
+ if (Array.isArray(input)) {
355
+ if (input.every((x) => typeof x === "number")) {
356
+ const tag = inferNumberTagFromSamples(input);
357
+ return array(withNumberTag(number(), tag));
358
+ }
359
+ if (input.length === 1) {
360
+ return array(auto(input[0], options));
361
+ }
362
+ return array(union(input.map((x) => auto(x, options))));
363
+ }
364
+ if (isPlainObject(input)) {
365
+ return mapping(remapObjectValues(input, ([_k, v]) => auto(v, options)));
366
+ }
367
+ return unknown();
368
+ }
369
+ }
370
+
371
+ export namespace shapes {
372
+ export const validate = _validate.validate;
373
+ export const is = _validate.is;
374
+ export const parse = _validate.parse;
375
+ }
376
+
377
+ export { annotate } from "./annotate";
@@ -0,0 +1,14 @@
1
+ export type FloatTag = "float" | "float32" | "float64";
2
+
3
+ export type IntTag =
4
+ | "int"
5
+ | "int8"
6
+ | "uint8"
7
+ | "int16"
8
+ | "uint16"
9
+ | "int32"
10
+ | "uint32"
11
+ | "int64"
12
+ | "uint64";
13
+
14
+ export type NumberTag = "number" | FloatTag | IntTag;
@@ -0,0 +1,3 @@
1
+ export * from "./json-schema";
2
+ export * from "./sql";
3
+ export * from "./typescript";
@@ -0,0 +1,2 @@
1
+ export * from "./types";
2
+ export * from "./transform";