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,50 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const LogLevel = B.union(
4
+ B.literal("trace"),
5
+ B.literal("debug"),
6
+ B.literal("info"),
7
+ B.literal("warn"),
8
+ B.literal("error"),
9
+ B.literal("fatal"),
10
+ );
11
+
12
+ export const DatabaseConfig = B.mapping({
13
+ driver: B.union(
14
+ B.literal("postgres"),
15
+ B.literal("mysql"),
16
+ B.literal("sqlite"),
17
+ ),
18
+ host: B.string().default("localhost"),
19
+ port: B.uint16(),
20
+ database: B.string().min(1),
21
+ user: B.string().optional(),
22
+ password: B.string().optional(),
23
+ poolSize: B.uint16().min(1).max(1000).default(10),
24
+ ssl: B.boolean().default(false),
25
+ });
26
+
27
+ export const RedisConfig = B.mapping({
28
+ url: B.string().regex(/^rediss?:\/\//),
29
+ prefix: B.string().optional(),
30
+ });
31
+
32
+ export const FeatureFlags = B.record(
33
+ B.string().regex(/^[a-z0-9_]+$/),
34
+ B.boolean(),
35
+ );
36
+
37
+ export const AppConfig = B.mapping({
38
+ env: B.union(
39
+ B.literal("development"),
40
+ B.literal("staging"),
41
+ B.literal("production"),
42
+ ),
43
+ logLevel: LogLevel.default("info"),
44
+ port: B.uint16().default(3000),
45
+ baseUrl: B.string().regex(/^https?:\/\//),
46
+ database: DatabaseConfig,
47
+ redis: RedisConfig.optional(),
48
+ features: FeatureFlags.default({}),
49
+ allowedOrigins: B.array(B.string()).uniqueItems().default([]),
50
+ });
@@ -0,0 +1,65 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const Currency = B.union(
4
+ B.literal("USD"),
5
+ B.literal("EUR"),
6
+ B.literal("GBP"),
7
+ B.literal("SEK"),
8
+ B.literal("NOK"),
9
+ );
10
+
11
+ export const Money = B.mapping({
12
+ amount: B.int64().describe("Smallest currency unit, e.g. cents"),
13
+ currency: Currency,
14
+ });
15
+
16
+ export const Customer = B.mapping({
17
+ id: B.uint64().primary().autoIncrement(),
18
+ email: B.string()
19
+ .regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)
20
+ .unique(),
21
+ name: B.string().min(1).max(120),
22
+ createdAt: B.date(),
23
+ }).title("Customer");
24
+
25
+ export const Product = B.mapping({
26
+ id: B.uint64().primary().autoIncrement(),
27
+ sku: B.string()
28
+ .regex(/^[A-Z0-9-]+$/)
29
+ .unique(),
30
+ name: B.string().min(1).max(200),
31
+ description: B.string().max(4000).optional(),
32
+ price: Money,
33
+ weightGrams: B.uint32().optional(),
34
+ tags: B.array(B.string().min(1).max(32)).max(20).uniqueItems(),
35
+ embedding: B.vector(1536, B.float32()).describe(
36
+ "OpenAI text-embedding-3-small",
37
+ ),
38
+ inStock: B.boolean().default(true),
39
+ }).title("Product");
40
+
41
+ export const OrderStatus = B.union(
42
+ B.literal("pending"),
43
+ B.literal("paid"),
44
+ B.literal("shipped"),
45
+ B.literal("delivered"),
46
+ B.literal("cancelled"),
47
+ B.literal("refunded"),
48
+ );
49
+
50
+ export const Order = B.mapping({
51
+ id: B.uint64().primary().autoIncrement(),
52
+ customer: B.uint64().references(Customer, "id"),
53
+ status: OrderStatus,
54
+ total: Money,
55
+ placedAt: B.date(),
56
+ shippedAt: B.date().optional(),
57
+ }).title("Order");
58
+
59
+ export const OrderLine = B.mapping({
60
+ id: B.uint64().primary().autoIncrement(),
61
+ order: B.uint64().references(Order, "id"),
62
+ product: B.uint64().references(Product, "id"),
63
+ quantity: B.uint32().min(1),
64
+ unitPrice: Money,
65
+ }).title("OrderLine");
@@ -0,0 +1,43 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const EmbeddingModel = B.union(
4
+ B.literal("text-embedding-3-small"),
5
+ B.literal("text-embedding-3-large"),
6
+ B.literal("voyage-3"),
7
+ B.literal("nomic-embed-text-v1.5"),
8
+ );
9
+
10
+ export const Document = B.mapping({
11
+ id: B.uint64().primary().autoIncrement(),
12
+ externalId: B.string().unique(),
13
+ title: B.string().min(1).max(500),
14
+ content: B.string(),
15
+ contentHash: B.string()
16
+ .regex(/^[a-f0-9]{64}$/)
17
+ .describe("SHA-256 hex"),
18
+ metadata: B.record(B.string(), B.string()).default({}),
19
+ createdAt: B.date(),
20
+ }).title("Document");
21
+
22
+ export const Chunk = B.mapping({
23
+ id: B.uint64().primary().autoIncrement(),
24
+ document: B.uint64().references(Document, "id"),
25
+ ordinal: B.uint32(),
26
+ text: B.string().min(1),
27
+ tokenCount: B.uint32(),
28
+ embeddingModel: EmbeddingModel,
29
+ embedding: B.vector(1536, B.float32()),
30
+ }).title("Chunk");
31
+
32
+ export const SearchHit = B.mapping({
33
+ chunk: B.uint64().references(Chunk, "id"),
34
+ score: B.float32().min(0).max(1),
35
+ snippet: B.string(),
36
+ });
37
+
38
+ export const SearchResult = B.mapping({
39
+ query: B.string(),
40
+ model: EmbeddingModel,
41
+ hits: B.array(SearchHit).max(100),
42
+ latencyMs: B.uint32(),
43
+ });
@@ -0,0 +1,52 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ const baseEvent = {
4
+ id: B.string().regex(/^evt_[a-zA-Z0-9]+$/),
5
+ occurredAt: B.date(),
6
+ };
7
+
8
+ export const UserSignedUpEvent = B.mapping({
9
+ ...baseEvent,
10
+ type: B.literal("user.signed_up"),
11
+ userId: B.uint64(),
12
+ email: B.string(),
13
+ referrer: B.string().optional(),
14
+ });
15
+
16
+ export const UserDeletedEvent = B.mapping({
17
+ ...baseEvent,
18
+ type: B.literal("user.deleted"),
19
+ userId: B.uint64(),
20
+ reason: B.union(
21
+ B.literal("self_serve"),
22
+ B.literal("admin"),
23
+ B.literal("gdpr"),
24
+ ),
25
+ });
26
+
27
+ export const PaymentSucceededEvent = B.mapping({
28
+ ...baseEvent,
29
+ type: B.literal("payment.succeeded"),
30
+ paymentId: B.uint64(),
31
+ userId: B.uint64(),
32
+ amount: B.int64(),
33
+ currency: B.string(),
34
+ });
35
+
36
+ export const PaymentFailedEvent = B.mapping({
37
+ ...baseEvent,
38
+ type: B.literal("payment.failed"),
39
+ paymentId: B.uint64(),
40
+ userId: B.uint64(),
41
+ amount: B.int64(),
42
+ currency: B.string(),
43
+ errorCode: B.string(),
44
+ errorMessage: B.string(),
45
+ });
46
+
47
+ export const Event = B.union(
48
+ UserSignedUpEvent,
49
+ UserDeletedEvent,
50
+ PaymentSucceededEvent,
51
+ PaymentFailedEvent,
52
+ );
@@ -0,0 +1,62 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const Vec2 = B.vector(2, B.float32());
4
+ export const Vec3 = B.vector(3, B.float32());
5
+ export const Vec4 = B.vector(4, B.float32());
6
+
7
+ // Tuple alternatives to the vectors above. `Vec3T` infers a TS
8
+ // `[number, number, number]` (positional) where `Vec3` infers `number[]`.
9
+ // Useful when downstream code needs structural destructuring rather than
10
+ // pgvector storage.
11
+ export const Vec3T = B.tuple(B.float32(), B.float32(), B.float32());
12
+
13
+ // A triangle as three positional vertices.
14
+ export const TriangleT = B.tuple(Vec3T, Vec3T, Vec3T);
15
+
16
+ // An edge in a mesh: a pair of vertex indices.
17
+ export const Edge = B.tuple(B.uint32(), B.uint32());
18
+
19
+ export const Color = B.mapping({
20
+ r: B.float32().min(0).max(1),
21
+ g: B.float32().min(0).max(1),
22
+ b: B.float32().min(0).max(1),
23
+ a: B.float32().min(0).max(1).default(1),
24
+ });
25
+
26
+ export const Circle = B.mapping({
27
+ kind: B.literal("circle"),
28
+ center: Vec2,
29
+ radius: B.float32().min(0),
30
+ fill: Color.optional(),
31
+ });
32
+
33
+ export const Rect = B.mapping({
34
+ kind: B.literal("rect"),
35
+ origin: Vec2,
36
+ size: Vec2,
37
+ fill: Color.optional(),
38
+ });
39
+
40
+ export const Polygon = B.mapping({
41
+ kind: B.literal("polygon"),
42
+ points: B.array(Vec2).min(3),
43
+ fill: Color.optional(),
44
+ });
45
+
46
+ export const Shape2D = B.union(Circle, Rect, Polygon);
47
+
48
+ export const Transform = B.mapping({
49
+ translation: Vec3,
50
+ rotation: Vec4.describe("Quaternion (x, y, z, w)"),
51
+ scale: Vec3.default([1, 1, 1]),
52
+ });
53
+
54
+ export const Mesh = B.mapping({
55
+ id: B.uint64().primary().autoIncrement(),
56
+ name: B.string().min(1).max(120),
57
+ vertices: B.array(Vec3),
58
+ normals: B.array(Vec3).optional(),
59
+ uvs: B.array(Vec2).optional(),
60
+ indices: B.array(B.uint32()),
61
+ transform: Transform,
62
+ }).title("Mesh");
@@ -0,0 +1,9 @@
1
+ export * as user from "./user";
2
+ export * as relational from "./relational";
3
+ export * as blog from "./blog";
4
+ export * as ecommerce from "./ecommerce";
5
+ export * as geometry from "./geometry";
6
+ export * as events from "./events";
7
+ export * as config from "./config";
8
+ export * as embeddings from "./embeddings";
9
+ export * as tuples from "./tuples";
@@ -0,0 +1,17 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const User = B.mapping({
4
+ id: B.uint64().primary().autoIncrement(),
5
+ firstname: B.string(),
6
+ lastname: B.string(),
7
+ email: B.string().regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/),
8
+ createdAt: B.date(),
9
+ }).title("User");
10
+
11
+ export const Payment = B.mapping({
12
+ id: B.uint64().primary().autoIncrement(),
13
+ user: B.uint64().references(User, "id"),
14
+ amount: B.int64(),
15
+ currency: B.string(),
16
+ createdAt: B.date(),
17
+ }).title("Payment");
@@ -0,0 +1,67 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ // RGB / RGBA as positional tuples — distinct from a Color mapping (no field
4
+ // names) and from B.vector (heterogeneous channel widths are possible).
5
+ export const RGB = B.tuple(B.uint8(), B.uint8(), B.uint8());
6
+ export const RGBA = B.tuple(
7
+ B.uint8(),
8
+ B.uint8(),
9
+ B.uint8(),
10
+ B.float32().min(0).max(1),
11
+ );
12
+
13
+ // Geographic coordinate: [latitude, longitude]. Tuple captures the convention
14
+ // that the order is meaningful — same shape would be ambiguous as `[number,
15
+ // number]` without the tuple positions.
16
+ export const LatLng = B.tuple(
17
+ B.float64().min(-90).max(90),
18
+ B.float64().min(-180).max(180),
19
+ );
20
+
21
+ // A bounding box in WGS84 as [south, west, north, east] (the GeoJSON / OGC bbox
22
+ // order). Four positional floats — natural fit for a tuple.
23
+ export const BBox = B.tuple(
24
+ B.float64().min(-90).max(90),
25
+ B.float64().min(-180).max(180),
26
+ B.float64().min(-90).max(90),
27
+ B.float64().min(-180).max(180),
28
+ );
29
+
30
+ // Inclusive half-open time interval: [startMillis, endMillis].
31
+ export const TimeRange = B.tuple(B.int64(), B.int64());
32
+
33
+ // A flat key/value entry — useful for serializing Map-shaped data positionally
34
+ // without the overhead of a `{key, value}` object.
35
+ export const StringEntry = B.tuple(B.string(), B.string());
36
+ export const Histogram = B.array(B.tuple(B.string(), B.uint32()));
37
+
38
+ // Heterogeneous record: a single audit log line.
39
+ // [timestamp, level, userId, message]
40
+ export const LogLine = B.tuple(
41
+ B.date(),
42
+ B.union(
43
+ B.literal("debug"),
44
+ B.literal("info"),
45
+ B.literal("warn"),
46
+ B.literal("error"),
47
+ ),
48
+ B.uint64(),
49
+ B.string(),
50
+ );
51
+
52
+ // A typed RPC call signature: [method, params, requestId].
53
+ export const RpcCall = B.tuple(B.string(), B.array(B.unknown()), B.uint64());
54
+
55
+ // Tuples nest cleanly. A 3D triangle as three vertex tuples.
56
+ const Vec3T = B.tuple(B.float32(), B.float32(), B.float32());
57
+ export const Triangle = B.tuple(Vec3T, Vec3T, Vec3T);
58
+
59
+ // A storable record that uses tuples in jsonb columns — toSQL emits a
60
+ // jsonb_array_length CHECK for each tuple column.
61
+ export const Waypoint = B.mapping({
62
+ id: B.uint64().primary().autoIncrement(),
63
+ name: B.string().min(1).max(120),
64
+ location: LatLng,
65
+ color: RGB,
66
+ visitedAt: B.date(),
67
+ }).title("Waypoint");
@@ -0,0 +1,9 @@
1
+ import { B } from "@shapecraft/core";
2
+
3
+ export const User = B.mapping({
4
+ id: B.uint64().primary().autoIncrement(),
5
+ firstname: B.string(),
6
+ lastname: B.string(),
7
+ email: B.string().regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/),
8
+ createdAt: B.date(),
9
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist/cjs",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node10",
7
+ "ignoreDeprecations": "6.0"
8
+ },
9
+ "include": ["./src/**/*.ts"],
10
+ "exclude": ["./src/**/*.test.ts", "./src/**/*.sample.ts"]
11
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist/esm",
5
+ "module": "esnext",
6
+ "target": "esnext"
7
+ },
8
+ "include": ["./src/**/*.ts"],
9
+ "exclude": ["./src/**/*.test.ts"]
10
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist/esm",
5
+ "module": "esnext",
6
+ "target": "esnext",
7
+ "lib": ["esnext"],
8
+ "types": ["node"],
9
+ "sourceMap": true,
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true,
14
+ "strict": true,
15
+ "isolatedModules": true,
16
+ "esModuleInterop": true,
17
+ "noUncheckedSideEffectImports": true,
18
+ "moduleDetection": "force",
19
+ "skipLibCheck": true
20
+ },
21
+ "include": ["./src/**/*.ts"],
22
+ "exclude": ["dist", "node_modules"]
23
+ }
@@ -0,0 +1,3 @@
1
+ packages:
2
+ - packages/*
3
+ - apps/*
@@ -0,0 +1,35 @@
1
+ {
2
+ "$id": "https://example.com/address.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "title": "address",
5
+ "description": "An address similar to http://microformats.org/wiki/h-card",
6
+ "type": "object",
7
+ "properties": {
8
+ "postOfficeBox": {
9
+ "type": "string"
10
+ },
11
+ "extendedAddress": {
12
+ "type": "string"
13
+ },
14
+ "streetAddress": {
15
+ "type": "string"
16
+ },
17
+ "locality": {
18
+ "type": "string"
19
+ },
20
+ "region": {
21
+ "type": "string"
22
+ },
23
+ "postalCode": {
24
+ "type": "string"
25
+ },
26
+ "countryName": {
27
+ "type": "string"
28
+ }
29
+ },
30
+ "required": [ "locality", "region", "countryName" ],
31
+ "dependentRequired": {
32
+ "postOfficeBox": [ "streetAddress" ],
33
+ "extendedAddress": [ "streetAddress" ]
34
+ }
35
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$id": "https://example.com/arrays.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "description": "Arrays of strings and objects",
5
+ "title": "Arrays",
6
+ "type": "object",
7
+ "properties": {
8
+ "fruits": {
9
+ "type": "array",
10
+ "items": {
11
+ "type": "string"
12
+ }
13
+ },
14
+ "vegetables": {
15
+ "type": "array",
16
+ "items": { "$ref": "#/$defs/veggie" }
17
+ }
18
+ },
19
+ "$defs": {
20
+ "veggie": {
21
+ "type": "object",
22
+ "required": [ "veggieName", "veggieLike" ],
23
+ "properties": {
24
+ "veggieName": {
25
+ "type": "string",
26
+ "description": "The name of the vegetable."
27
+ },
28
+ "veggieLike": {
29
+ "type": "boolean",
30
+ "description": "Do I like this vegetable?"
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+
@@ -0,0 +1,21 @@
1
+ {
2
+ "$id": "https://example.com/person.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "title": "Person",
5
+ "type": "object",
6
+ "properties": {
7
+ "firstName": {
8
+ "type": "string",
9
+ "description": "The person's first name."
10
+ },
11
+ "lastName": {
12
+ "type": "string",
13
+ "description": "The person's last name."
14
+ },
15
+ "age": {
16
+ "description": "Age in years which must be equal to or greater than zero.",
17
+ "type": "integer",
18
+ "minimum": 0
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$id": "https://example.com/blog-post.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "title": "blog-post",
5
+ "description": "A representation of a blog post",
6
+ "type": "object",
7
+ "required": ["title", "content", "author"],
8
+ "properties": {
9
+ "title": {
10
+ "type": "string"
11
+ },
12
+ "content": {
13
+ "type": "string"
14
+ },
15
+ "publishedDate": {
16
+ "type": "string",
17
+ "format": "date-time"
18
+ },
19
+ "author": {
20
+ "$ref": "https://example.com/user-profile.schema.json"
21
+ },
22
+ "tags": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "string"
26
+ }
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "$id": "https://example.com/calendar.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "title": "calendar",
5
+ "description": "A representation of an event",
6
+ "type": "object",
7
+ "required": [ "dtstart", "summary" ],
8
+ "properties": {
9
+ "startDate": {
10
+ "type": "string",
11
+ "description": "Event starting time"
12
+ },
13
+ "endDate": {
14
+ "type": "string",
15
+ "description": "Event ending time"
16
+ },
17
+ "summary": {
18
+ "type": "string"
19
+ },
20
+ "location": {
21
+ "type": "string"
22
+ },
23
+ "url": {
24
+ "type": "string"
25
+ },
26
+ "duration": {
27
+ "type": "string",
28
+ "description": "Event duration"
29
+ },
30
+ "recurrenceDate": {
31
+ "type": "string",
32
+ "description": "Recurrence date"
33
+ },
34
+ "recurrenceDule": {
35
+ "type": "string",
36
+ "description": "Recurrence rule"
37
+ },
38
+ "category": {
39
+ "type": "string"
40
+ },
41
+ "description": {
42
+ "type": "string"
43
+ },
44
+ "geo": {
45
+ "$ref": "https://example.com/geographical-location.schema.json"
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "$id": "https://example.com/complex-object.schema.json",
3
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
4
+ "title": "Complex Object",
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string"
9
+ },
10
+ "age": {
11
+ "type": "integer",
12
+ "minimum": 0
13
+ },
14
+ "address": {
15
+ "type": "object",
16
+ "properties": {
17
+ "street": {
18
+ "type": "string"
19
+ },
20
+ "city": {
21
+ "type": "string"
22
+ },
23
+ "state": {
24
+ "type": "string"
25
+ },
26
+ "postalCode": {
27
+ "type": "string",
28
+ "pattern": "\\d{5}"
29
+ }
30
+ },
31
+ "required": ["street", "city", "state", "postalCode"]
32
+ },
33
+ "hobbies": {
34
+ "type": "array",
35
+ "items": {
36
+ "type": "string"
37
+ }
38
+ }
39
+ },
40
+ "required": ["name", "age"]
41
+ }