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.
- package/CLAUDE.md +227 -0
- package/README.md +22 -0
- package/apps/cli/node_modules/.bin/prettier +21 -0
- package/apps/cli/node_modules/.bin/tsc +21 -0
- package/apps/cli/node_modules/.bin/tsserver +21 -0
- package/apps/cli/node_modules/.bin/tsx +21 -0
- package/apps/cli/node_modules/.bin/vitest +21 -0
- package/apps/cli/package.json +47 -0
- package/apps/cli/src/index.ts +98 -0
- package/apps/cli/tsconfig.cjs.json +10 -0
- package/apps/cli/tsconfig.esm.json +10 -0
- package/apps/cli/tsconfig.json +22 -0
- package/package.json +16 -0
- package/packages/core/node_modules/.bin/prettier +21 -0
- package/packages/core/node_modules/.bin/tsc +21 -0
- package/packages/core/node_modules/.bin/tsserver +21 -0
- package/packages/core/node_modules/.bin/tsx +21 -0
- package/packages/core/node_modules/.bin/vitest +21 -0
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/core/package.json +44 -0
- package/packages/core/src/common/array.test.ts +19 -0
- package/packages/core/src/common/array.ts +15 -0
- package/packages/core/src/common/index.ts +5 -0
- package/packages/core/src/common/is.ts +23 -0
- package/packages/core/src/common/object.ts +35 -0
- package/packages/core/src/common/phantom.ts +1 -0
- package/packages/core/src/common/result.ts +43 -0
- package/packages/core/src/common/string.ts +28 -0
- package/packages/core/src/common/types.ts +34 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/shape/annotate.ts +139 -0
- package/packages/core/src/shape/annotation.ts +47 -0
- package/packages/core/src/shape/base.ts +71 -0
- package/packages/core/src/shape/builder.test.ts +728 -0
- package/packages/core/src/shape/builder.ts +475 -0
- package/packages/core/src/shape/error.ts +4 -0
- package/packages/core/src/shape/index.ts +3 -0
- package/packages/core/src/shape/number.ts +118 -0
- package/packages/core/src/shape/shape.test.ts +792 -0
- package/packages/core/src/shape/shape.ts +377 -0
- package/packages/core/src/shape/tags.ts +14 -0
- package/packages/core/src/shape/transforms/index.ts +3 -0
- package/packages/core/src/shape/transforms/json-schema/index.ts +2 -0
- package/packages/core/src/shape/transforms/json-schema/transform.test.ts +850 -0
- package/packages/core/src/shape/transforms/json-schema/transform.ts +882 -0
- package/packages/core/src/shape/transforms/json-schema/types.ts +132 -0
- package/packages/core/src/shape/transforms/sql/dialects/dialect.ts +89 -0
- package/packages/core/src/shape/transforms/sql/dialects/index.ts +14 -0
- package/packages/core/src/shape/transforms/sql/dialects/postgres.ts +392 -0
- package/packages/core/src/shape/transforms/sql/dialects/sqlite.ts +333 -0
- package/packages/core/src/shape/transforms/sql/from-sql.test.ts +704 -0
- package/packages/core/src/shape/transforms/sql/from-sql.ts +210 -0
- package/packages/core/src/shape/transforms/sql/index.ts +3 -0
- package/packages/core/src/shape/transforms/sql/options.ts +6 -0
- package/packages/core/src/shape/transforms/sql/parser/check-decoder.ts +457 -0
- package/packages/core/src/shape/transforms/sql/parser/create-domain.ts +105 -0
- package/packages/core/src/shape/transforms/sql/parser/create-table.ts +809 -0
- package/packages/core/src/shape/transforms/sql/parser/create-type.ts +91 -0
- package/packages/core/src/shape/transforms/sql/parser/cursor.ts +179 -0
- package/packages/core/src/shape/transforms/sql/parser/default-decoder.ts +129 -0
- package/packages/core/src/shape/transforms/sql/parser/lexer.ts +289 -0
- package/packages/core/src/shape/transforms/sql/parser/pg-types.ts +247 -0
- package/packages/core/src/shape/transforms/sql/parser/sqlite-types.ts +103 -0
- package/packages/core/src/shape/transforms/sql/parser/statements.ts +127 -0
- package/packages/core/src/shape/transforms/sql/parser/type-spec.ts +159 -0
- package/packages/core/src/shape/transforms/sql/transform.sqlite.test.ts +448 -0
- package/packages/core/src/shape/transforms/sql/transform.test.ts +880 -0
- package/packages/core/src/shape/transforms/sql/transform.ts +295 -0
- package/packages/core/src/shape/transforms/typescript/index.ts +1 -0
- package/packages/core/src/shape/transforms/typescript/transform.ts +211 -0
- package/packages/core/src/shape/tuple.test.ts +171 -0
- package/packages/core/src/shape/validate.ts +413 -0
- package/packages/core/tsconfig.cjs.json +11 -0
- package/packages/core/tsconfig.esm.json +10 -0
- package/packages/core/tsconfig.json +23 -0
- package/packages/samples/node_modules/.bin/prettier +21 -0
- package/packages/samples/node_modules/.bin/tsc +21 -0
- package/packages/samples/node_modules/.bin/tsserver +21 -0
- package/packages/samples/node_modules/.bin/tsx +21 -0
- package/packages/samples/node_modules/.bin/vitest +21 -0
- package/packages/samples/package.json +47 -0
- package/packages/samples/src/blog.ts +49 -0
- package/packages/samples/src/config.ts +50 -0
- package/packages/samples/src/ecommerce.ts +65 -0
- package/packages/samples/src/embeddings.ts +43 -0
- package/packages/samples/src/events.ts +52 -0
- package/packages/samples/src/geometry.ts +62 -0
- package/packages/samples/src/index.ts +9 -0
- package/packages/samples/src/relational.ts +17 -0
- package/packages/samples/src/tuples.ts +67 -0
- package/packages/samples/src/user.ts +9 -0
- package/packages/samples/tsconfig.cjs.json +11 -0
- package/packages/samples/tsconfig.esm.json +10 -0
- package/packages/samples/tsconfig.json +23 -0
- package/pnpm-workspace.yaml +3 -0
- package/test-data/json-schema/address.json +35 -0
- package/test-data/json-schema/array-of-things.json +36 -0
- package/test-data/json-schema/basic.json +21 -0
- package/test-data/json-schema/blog-post.json +29 -0
- package/test-data/json-schema/calendar.json +48 -0
- package/test-data/json-schema/complex-object-with-nested-properties.json +41 -0
- package/test-data/json-schema/ecommerce-complex.json +344 -0
- package/test-data/json-schema/ecommerce-system.json +27 -0
- package/test-data/json-schema/enumerated-values.json +11 -0
- package/test-data/json-schema/fstab-entry.json +92 -0
- package/test-data/json-schema/geographical-location.json +20 -0
- package/test-data/json-schema/health-record.json +41 -0
- package/test-data/json-schema/job-posting.json +33 -0
- package/test-data/json-schema/movie.json +35 -0
- package/test-data/json-schema/regular-expression-pattern.json +12 -0
- package/test-data/json-schema/user-profile.json +33 -0
- package/test-data/sql/ecommerce.sql +641 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules/tsx/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules/tsx/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules/vitest/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules/vitest/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../vitest/vitest.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"4.1.6","results":[[":src/shape/transforms/json-schema/transform.test.ts",{"duration":21.738624999999956,"failed":false}],[":src/shape/transforms/sql/transform.test.ts",{"duration":16.188017000000002,"failed":false}],[":src/shape/builder.test.ts",{"duration":27.164341000000036,"failed":false}],[":src/shape/transforms/sql/from-sql.test.ts",{"duration":51.94062199999996,"failed":false}],[":src/shape/transforms/sql/transform.sqlite.test.ts",{"duration":29.056380999999988,"failed":false}],[":src/common/array.test.ts",{"duration":4.342939000000001,"failed":false}],[":src/shape/shape.test.ts",{"duration":26.323568000000023,"failed":false}],[":src/shape/tuple.test.ts",{"duration":11.398279000000002,"failed":false}]]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shapecraft/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "vitest --passWithNoTests","check":
|
|
8
|
+
"tsc -p ./tsconfig.json --noEmit",
|
|
9
|
+
"format": "prettier --experimental-ternaries ./src --write",
|
|
10
|
+
"build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"packageManager": "pnpm@10.33.2",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^25.8.0",
|
|
18
|
+
"prettier": "^3.8.3",
|
|
19
|
+
"tsx": "^4.22.0",
|
|
20
|
+
"typescript": "^6.0.3",
|
|
21
|
+
"vitest": "^4.1.6"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"main": "./dist/cjs/index.js",
|
|
25
|
+
"types": "./dist/cjs/index.d.ts",
|
|
26
|
+
"typings": "./dist/cjs/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": {
|
|
30
|
+
"types": "./dist/esm/index.d.ts",
|
|
31
|
+
"default": "./dist/esm/index.js"
|
|
32
|
+
},
|
|
33
|
+
"require": {
|
|
34
|
+
"types": "./dist/cjs/index.d.ts",
|
|
35
|
+
"default": "./dist/cjs/index.js"
|
|
36
|
+
},
|
|
37
|
+
"default": {
|
|
38
|
+
"types": "./dist/cjs/index.d.ts",
|
|
39
|
+
"default": "./dist/cjs/index.js"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect } from "vitest";
|
|
2
|
+
import { uniqueBy } from "./array";
|
|
3
|
+
|
|
4
|
+
describe("uniqueBy", (it) => {
|
|
5
|
+
it("returns a unique array", () => {
|
|
6
|
+
const items: Array<{ firstname: string; lastname: string }> = [
|
|
7
|
+
{ firstname: "john", lastname: "doe" },
|
|
8
|
+
{ firstname: "john", lastname: "david" },
|
|
9
|
+
{ firstname: "david", lastname: "doe" },
|
|
10
|
+
{ firstname: "sarah", lastname: "sharp" },
|
|
11
|
+
{ firstname: "john", lastname: "doe" },
|
|
12
|
+
{ firstname: "john", lastname: "doe" },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const un = uniqueBy(items, (x) => x.firstname);
|
|
16
|
+
|
|
17
|
+
expect(un.length).toBe(3);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const range = (n: number): Array<number> =>
|
|
2
|
+
n < 1 ? [] : Array.from(Array(Math.trunc(n)).keys());
|
|
3
|
+
|
|
4
|
+
export const uniqueBy = <T, Fn extends (x: T) => any>(
|
|
5
|
+
arr: T[],
|
|
6
|
+
fn: Fn,
|
|
7
|
+
): T[] => {
|
|
8
|
+
const seen = new Set<ReturnType<Fn>>();
|
|
9
|
+
return arr.filter((x) => {
|
|
10
|
+
const k = fn(x);
|
|
11
|
+
if (seen.has(k)) return false;
|
|
12
|
+
seen.add(k);
|
|
13
|
+
return true;
|
|
14
|
+
});
|
|
15
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const isPlainObject = (x: any): x is Record<PropertyKey, unknown> => {
|
|
2
|
+
if (x === null || typeof x === "undefined") return false;
|
|
3
|
+
if (Array.isArray(x)) return false;
|
|
4
|
+
if (x instanceof Date) return false;
|
|
5
|
+
if (typeof x !== "object") return false;
|
|
6
|
+
return Object.getPrototypeOf(x) === Object.prototype;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const isSafeNumber = (x: number): boolean => {
|
|
10
|
+
if (isNaN(x)) return false;
|
|
11
|
+
if (!isFinite(x)) return false;
|
|
12
|
+
return true;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const isSafeFloat = (x: number): boolean => {
|
|
16
|
+
if (!isSafeNumber(x)) return false;
|
|
17
|
+
if (Number.isInteger(x)) return false;
|
|
18
|
+
return true;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const isNumeric = (str: string): boolean => {
|
|
22
|
+
return !isNaN(Number(str)) && !isNaN(parseFloat(str));
|
|
23
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { LooseRecord } from "./types";
|
|
2
|
+
|
|
3
|
+
export const remapObjectValues = <
|
|
4
|
+
Obj extends LooseRecord,
|
|
5
|
+
Fn extends (kv: [keyof Obj, Obj[keyof Obj]]) => any,
|
|
6
|
+
>(
|
|
7
|
+
obj: Obj,
|
|
8
|
+
fn: Fn,
|
|
9
|
+
): Record<keyof Obj, ReturnType<Fn>> => {
|
|
10
|
+
const entries = Object.entries(obj) as Array<[keyof Obj, Obj[keyof Obj]]>;
|
|
11
|
+
return Object.assign(
|
|
12
|
+
{},
|
|
13
|
+
...entries.map((kv) => {
|
|
14
|
+
return {
|
|
15
|
+
[kv[0]]: fn(kv),
|
|
16
|
+
};
|
|
17
|
+
}),
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const remapObjectEntries = <
|
|
22
|
+
Obj extends LooseRecord,
|
|
23
|
+
Fn extends (kv: [keyof Obj, Obj[keyof Obj]]) => LooseRecord,
|
|
24
|
+
>(
|
|
25
|
+
obj: Obj,
|
|
26
|
+
fn: Fn,
|
|
27
|
+
): ReturnType<Fn> => {
|
|
28
|
+
const entries = Object.entries(obj) as Array<[keyof Obj, Obj[keyof Obj]]>;
|
|
29
|
+
return Object.assign(
|
|
30
|
+
{},
|
|
31
|
+
...entries.map((kv) => {
|
|
32
|
+
return fn(kv);
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type PhantomType = any;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isPlainObject } from "./is";
|
|
2
|
+
|
|
3
|
+
export namespace R {
|
|
4
|
+
export type ResultOk<T> = {
|
|
5
|
+
value: T;
|
|
6
|
+
ok: true;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type ResultErr<E> = {
|
|
10
|
+
error: E;
|
|
11
|
+
ok: false;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type Result<T, E> = ResultOk<T> | ResultErr<E>;
|
|
15
|
+
|
|
16
|
+
export type LooseResult = Result<any, any>;
|
|
17
|
+
|
|
18
|
+
export function isResult(x: unknown): x is Result<any, any> {
|
|
19
|
+
return isPlainObject(x) && typeof x["ok"] === "boolean" && "value" in x;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isOk<Res extends LooseResult>(
|
|
23
|
+
res: LooseResult,
|
|
24
|
+
): res is Extract<Res, { ok: true }> {
|
|
25
|
+
return res.ok === true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isErr<Res extends LooseResult>(
|
|
29
|
+
res: LooseResult,
|
|
30
|
+
): res is Extract<Res, { ok: false }> {
|
|
31
|
+
return res.ok === false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const err = <E>(error: E): ResultErr<E> => ({
|
|
35
|
+
error,
|
|
36
|
+
ok: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const ok = <T>(value: T): ResultOk<T> => ({
|
|
40
|
+
value,
|
|
41
|
+
ok: true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { range } from "./array";
|
|
2
|
+
|
|
3
|
+
export const repeat = (x: string, n: number): string =>
|
|
4
|
+
range(n)
|
|
5
|
+
.map(() => x)
|
|
6
|
+
.join("");
|
|
7
|
+
|
|
8
|
+
export const forceString = (x: unknown): string => {
|
|
9
|
+
if (typeof x === "string") return x;
|
|
10
|
+
if (x === null) return "null";
|
|
11
|
+
if (typeof x === "object") {
|
|
12
|
+
const r = x as Record<string, unknown>;
|
|
13
|
+
if (
|
|
14
|
+
typeof r.toString === "function" &&
|
|
15
|
+
r.toString !== Object.prototype.toString
|
|
16
|
+
) {
|
|
17
|
+
try {
|
|
18
|
+
const ret = r.toString();
|
|
19
|
+
if (typeof ret === "string") return ret;
|
|
20
|
+
} catch {}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
return JSON.stringify(x);
|
|
25
|
+
} catch {}
|
|
26
|
+
|
|
27
|
+
return "";
|
|
28
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type Tuple<T> =
|
|
2
|
+
| [T]
|
|
3
|
+
| [T, T]
|
|
4
|
+
| [T, T, T]
|
|
5
|
+
| [T, T, T, T]
|
|
6
|
+
| [T, ...T[]]
|
|
7
|
+
| [...T[], T];
|
|
8
|
+
|
|
9
|
+
export type Arrayish<T> = Tuple<T> | Array<T>;
|
|
10
|
+
|
|
11
|
+
export type Prettify<T> = {
|
|
12
|
+
[K in keyof T]: T[K];
|
|
13
|
+
} & {};
|
|
14
|
+
|
|
15
|
+
export type LooseRecord = Record<PropertyKey, any>;
|
|
16
|
+
|
|
17
|
+
export type Binary = Uint8Array | number[];
|
|
18
|
+
|
|
19
|
+
type UnionToIntersection<U> =
|
|
20
|
+
(U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I
|
|
21
|
+
: never;
|
|
22
|
+
|
|
23
|
+
type LastOf<T> =
|
|
24
|
+
UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R
|
|
25
|
+
: never;
|
|
26
|
+
|
|
27
|
+
type Push<T extends any[], V> = [...T, V];
|
|
28
|
+
|
|
29
|
+
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
|
|
30
|
+
true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
|
|
31
|
+
|
|
32
|
+
export type UnionToTuple<T, A extends T[] = []> =
|
|
33
|
+
TuplifyUnion<T>["length"] extends A["length"] ? [...A]
|
|
34
|
+
: UnionToTuple<T, [T, ...A]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./shape";
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Annotation } from "./annotation";
|
|
2
|
+
import { shapes } from "./shape";
|
|
3
|
+
|
|
4
|
+
export namespace annotate {
|
|
5
|
+
export function as<const S extends shapes.Shape, Anno extends Annotation>(
|
|
6
|
+
shape: S,
|
|
7
|
+
anno: Anno,
|
|
8
|
+
): shapes.Annotated<S, Anno> {
|
|
9
|
+
return {
|
|
10
|
+
...shape,
|
|
11
|
+
anno: {
|
|
12
|
+
...shape.anno,
|
|
13
|
+
...anno,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const optional = <const S extends shapes.Shape>(
|
|
19
|
+
shape: S,
|
|
20
|
+
): shapes.Annotated<S, { optional: true }> => as(shape, { optional: true });
|
|
21
|
+
|
|
22
|
+
export const unique = <const S extends shapes.Shape>(
|
|
23
|
+
shape: S,
|
|
24
|
+
): shapes.Annotated<S, { unique: true }> => as(shape, { unique: true });
|
|
25
|
+
|
|
26
|
+
export const uniqueItems = <const S extends shapes.ShapeArray>(
|
|
27
|
+
shape: S,
|
|
28
|
+
): shapes.Annotated<S, { uniqueItems: true }> =>
|
|
29
|
+
as(shape, { uniqueItems: true });
|
|
30
|
+
|
|
31
|
+
export const primary = <const S extends shapes.Shape>(
|
|
32
|
+
shape: S,
|
|
33
|
+
): shapes.Annotated<S, { primary: true }> => as(shape, { primary: true });
|
|
34
|
+
|
|
35
|
+
export const defaulted = <
|
|
36
|
+
const S extends shapes.Shape,
|
|
37
|
+
Value extends shapes.InferShapeOut<S>,
|
|
38
|
+
>(
|
|
39
|
+
shape: S,
|
|
40
|
+
value: Value,
|
|
41
|
+
): shapes.Annotated<S, { default: Value }> => as(shape, { default: value });
|
|
42
|
+
|
|
43
|
+
export const described = <
|
|
44
|
+
const S extends shapes.Shape,
|
|
45
|
+
Description extends string,
|
|
46
|
+
>(
|
|
47
|
+
shape: S,
|
|
48
|
+
description: Description,
|
|
49
|
+
): shapes.Annotated<S, { description: Description }> =>
|
|
50
|
+
as(shape, { description: description });
|
|
51
|
+
|
|
52
|
+
export const titled = <const S extends shapes.Shape, Title extends string>(
|
|
53
|
+
shape: S,
|
|
54
|
+
title: Title,
|
|
55
|
+
): shapes.Annotated<S, { title: Title }> => as(shape, { title: title });
|
|
56
|
+
|
|
57
|
+
export const commented = <
|
|
58
|
+
const S extends shapes.Shape,
|
|
59
|
+
Comment extends string,
|
|
60
|
+
>(
|
|
61
|
+
shape: S,
|
|
62
|
+
comment: Comment,
|
|
63
|
+
): shapes.Annotated<S, { comment: Comment }> =>
|
|
64
|
+
as(shape, { comment: comment });
|
|
65
|
+
|
|
66
|
+
export const autoIncremented = <const S extends shapes.Shape>(
|
|
67
|
+
shape: S,
|
|
68
|
+
): shapes.Annotated<S, { autoIncrement: true }> =>
|
|
69
|
+
as(shape, { autoIncrement: true });
|
|
70
|
+
|
|
71
|
+
export const foreign = <
|
|
72
|
+
const S extends shapes.Shape,
|
|
73
|
+
Table extends string,
|
|
74
|
+
Column extends string,
|
|
75
|
+
>(
|
|
76
|
+
shape: S,
|
|
77
|
+
table: Table,
|
|
78
|
+
column: Column,
|
|
79
|
+
): shapes.Annotated<S, { foreign: { table: Table; column: Column } }> =>
|
|
80
|
+
as(shape, { foreign: { table, column } });
|
|
81
|
+
|
|
82
|
+
export const min = <
|
|
83
|
+
const S extends shapes.ShapeString | shapes.ShapeNumber | shapes.ShapeArray,
|
|
84
|
+
Min extends number,
|
|
85
|
+
>(
|
|
86
|
+
shape: S,
|
|
87
|
+
min: Min,
|
|
88
|
+
): shapes.Annotated<S, { min: Min }> => as(shape, { min });
|
|
89
|
+
|
|
90
|
+
export const max = <
|
|
91
|
+
const S extends shapes.ShapeString | shapes.ShapeNumber | shapes.ShapeArray,
|
|
92
|
+
Max extends number,
|
|
93
|
+
>(
|
|
94
|
+
shape: S,
|
|
95
|
+
max: Max,
|
|
96
|
+
): shapes.Annotated<S, { max: Max }> => as(shape, { max });
|
|
97
|
+
|
|
98
|
+
export const pattern = <
|
|
99
|
+
const S extends shapes.ShapeString,
|
|
100
|
+
const P extends string | RegExp,
|
|
101
|
+
>(
|
|
102
|
+
shape: S,
|
|
103
|
+
pattern: P,
|
|
104
|
+
): shapes.Annotated<S, { pattern: P }> => as(shape, { pattern });
|
|
105
|
+
|
|
106
|
+
export const format = <
|
|
107
|
+
const S extends shapes.ShapeString,
|
|
108
|
+
const F extends string,
|
|
109
|
+
>(
|
|
110
|
+
shape: S,
|
|
111
|
+
format: F,
|
|
112
|
+
): shapes.Annotated<S, { format: F }> => as(shape, { format });
|
|
113
|
+
|
|
114
|
+
export const uuid = <S extends shapes.ShapeString>(
|
|
115
|
+
shape: S,
|
|
116
|
+
version?: number | undefined,
|
|
117
|
+
): shapes.Annotated<S, { pattern: RegExp }> => {
|
|
118
|
+
return as(
|
|
119
|
+
pattern(
|
|
120
|
+
shape,
|
|
121
|
+
version ?
|
|
122
|
+
new RegExp(
|
|
123
|
+
`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`,
|
|
124
|
+
)
|
|
125
|
+
: /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/,
|
|
126
|
+
),
|
|
127
|
+
{ uuidVersion: version },
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const meta = <
|
|
132
|
+
const S extends shapes.Shape,
|
|
133
|
+
Meta extends Record<string, any>,
|
|
134
|
+
>(
|
|
135
|
+
shape: S,
|
|
136
|
+
meta: Meta,
|
|
137
|
+
): shapes.Annotated<S, { meta: S["anno"]["meta"] & Meta }> =>
|
|
138
|
+
as(shape, { meta: { ...(shape.anno.meta || {}), ...meta } });
|
|
139
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type ReferentialAction =
|
|
2
|
+
| "cascade"
|
|
3
|
+
| "restrict"
|
|
4
|
+
| "setNull"
|
|
5
|
+
| "setDefault"
|
|
6
|
+
| "noAction";
|
|
7
|
+
|
|
8
|
+
export type Annotation = {
|
|
9
|
+
optional?: boolean;
|
|
10
|
+
min?: number;
|
|
11
|
+
max?: number;
|
|
12
|
+
unique?: boolean;
|
|
13
|
+
uniqueItems?: boolean;
|
|
14
|
+
// Mapping-level multi-column UNIQUE constraints (single-column UNIQUE
|
|
15
|
+
// still lives on the column via `unique: true`).
|
|
16
|
+
uniqueConstraints?: Array<{
|
|
17
|
+
columns: string[];
|
|
18
|
+
name?: string;
|
|
19
|
+
}>;
|
|
20
|
+
primary?: boolean;
|
|
21
|
+
autoIncrement?: boolean;
|
|
22
|
+
pattern?: string | RegExp;
|
|
23
|
+
format?: string;
|
|
24
|
+
foreign?: {
|
|
25
|
+
table: string;
|
|
26
|
+
column: string;
|
|
27
|
+
onDelete?: ReferentialAction;
|
|
28
|
+
onUpdate?: ReferentialAction;
|
|
29
|
+
};
|
|
30
|
+
default?: unknown;
|
|
31
|
+
defaultExpr?: string;
|
|
32
|
+
check?: string;
|
|
33
|
+
generated?: {
|
|
34
|
+
expression: string;
|
|
35
|
+
stored: boolean;
|
|
36
|
+
};
|
|
37
|
+
schema?: string;
|
|
38
|
+
title?: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
comment?: string;
|
|
41
|
+
uuidVersion?: number | undefined;
|
|
42
|
+
meta?: Record<string, any>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type AnnotatedLoose = {
|
|
46
|
+
anno: Annotation;
|
|
47
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PhantomType } from "../common";
|
|
2
|
+
import { Annotation } from "./annotation";
|
|
3
|
+
|
|
4
|
+
export interface _ShapePhantom {
|
|
5
|
+
output: PhantomType;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type _WithPhantom = {
|
|
9
|
+
_: _ShapePhantom;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export interface ShapeLooseBase {
|
|
13
|
+
type: string;
|
|
14
|
+
anno: Annotation;
|
|
15
|
+
_shape: true;
|
|
16
|
+
_: _ShapePhantom;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type ShapeBase<
|
|
20
|
+
Type extends string,
|
|
21
|
+
Input = PhantomType,
|
|
22
|
+
Output = PhantomType,
|
|
23
|
+
> = Omit<ShapeLooseBase, "_"> & {
|
|
24
|
+
type: Type;
|
|
25
|
+
input: Input;
|
|
26
|
+
anno: Annotation;
|
|
27
|
+
|
|
28
|
+
_: {
|
|
29
|
+
output: Output;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type ShapeLoose<Type extends string = string> = ShapeBase<
|
|
34
|
+
Type,
|
|
35
|
+
PhantomType,
|
|
36
|
+
PhantomType
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
export const createPhantom = (): _WithPhantom => ({}) as PhantomType;
|
|
40
|
+
|
|
41
|
+
export function createBaseWithPhantom<const Type extends string>(
|
|
42
|
+
type: Type,
|
|
43
|
+
): {
|
|
44
|
+
type: Type;
|
|
45
|
+
input: null;
|
|
46
|
+
anno: Annotation;
|
|
47
|
+
_shape: true;
|
|
48
|
+
_: _ShapePhantom;
|
|
49
|
+
} {
|
|
50
|
+
return {
|
|
51
|
+
...createPhantom(),
|
|
52
|
+
input: null,
|
|
53
|
+
type: type,
|
|
54
|
+
anno: {},
|
|
55
|
+
_shape: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createBaseWithInput<
|
|
60
|
+
const Type extends string,
|
|
61
|
+
const Input,
|
|
62
|
+
Output,
|
|
63
|
+
>(type: Type, input: Input): ShapeBase<Type, Input, Output> {
|
|
64
|
+
return {
|
|
65
|
+
type: type,
|
|
66
|
+
input: input,
|
|
67
|
+
...createPhantom(),
|
|
68
|
+
_shape: true,
|
|
69
|
+
anno: {},
|
|
70
|
+
};
|
|
71
|
+
}
|