@prisma-next/contract 0.14.0-dev.3 → 0.14.0-dev.31
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/dist/enum-accessor.d.mts +4 -21
- package/dist/enum-accessor.d.mts.map +1 -1
- package/dist/enum-accessor.mjs +2 -14
- package/dist/enum-accessor.mjs.map +1 -1
- package/package.json +4 -4
- package/src/enum-accessor.ts +15 -52
package/dist/enum-accessor.d.mts
CHANGED
|
@@ -22,29 +22,12 @@ interface EnumAccessor {
|
|
|
22
22
|
ordinalOf(v: JsonValue): number;
|
|
23
23
|
}
|
|
24
24
|
declare function createEnumAccessor(contractEnum: ContractEnum): EnumAccessor;
|
|
25
|
-
/**
|
|
26
|
-
* Build the enum-accessor map for a single namespace, keyed by enum name.
|
|
27
|
-
* Each namespace facet exposes only its own enums — the IR keys enums under
|
|
28
|
-
* `domain.namespaces[ns].enum`, so the same name in two namespaces resolves
|
|
29
|
-
* independently rather than colliding in one flat map.
|
|
30
|
-
*/
|
|
31
25
|
declare function buildEnumsMapForNamespace(domain: {
|
|
32
26
|
readonly namespaces: Readonly<Record<string, {
|
|
33
27
|
readonly enum?: Readonly<Record<string, ContractEnum>>;
|
|
34
28
|
}>>;
|
|
35
29
|
}, namespaceId: string): Record<string, EnumAccessor>;
|
|
36
|
-
|
|
37
|
-
* Build the enum-accessor map for every namespace of a domain, keyed by
|
|
38
|
-
* namespace id then enum name. This is the lane-agnostic enum surface the
|
|
39
|
-
* `db.enums` facade member exposes: enums are contract metadata, the same
|
|
40
|
-
* whether reached through the sql lane or the orm lane, so the facade builds
|
|
41
|
-
* this once and projects it per target.
|
|
42
|
-
*/
|
|
43
|
-
declare function buildNamespacedEnums(domain: {
|
|
44
|
-
readonly namespaces: Readonly<Record<string, {
|
|
45
|
-
readonly enum?: Readonly<Record<string, ContractEnum>>;
|
|
46
|
-
}>>;
|
|
47
|
-
}): Record<string, Record<string, EnumAccessor>>;
|
|
30
|
+
declare function buildNamespacedEnums<TContract extends Contract>(domain: TContract['domain']): NamespacedEnums<TContract>;
|
|
48
31
|
type Present<T> = Exclude<T, undefined>;
|
|
49
32
|
type EnumMemberEntry = {
|
|
50
33
|
readonly name: string;
|
|
@@ -81,12 +64,12 @@ type EnumMemberNames<A> = A extends {
|
|
|
81
64
|
} ? N : never;
|
|
82
65
|
type EnumEntriesToAccessors<Enums> = { readonly [K in keyof Enums]: Enums[K] extends EnumEntry ? ContractEnumAccessor<Enums[K]> : never };
|
|
83
66
|
type BuiltEnumAccessorsOf<TContract> = TContract extends {
|
|
84
|
-
readonly enumAccessors
|
|
85
|
-
} ? A : Record<never, never>;
|
|
67
|
+
readonly enumAccessors?: infer A;
|
|
68
|
+
} ? Exclude<A, undefined> : Record<never, never>;
|
|
86
69
|
type NamespaceEnumEntries<TNamespace> = TNamespace extends {
|
|
87
70
|
readonly enum?: infer E;
|
|
88
71
|
} ? unknown extends E ? Record<never, never> : Present<E> : Record<never, never>;
|
|
89
|
-
type NamespaceEnumAccessors<TContract extends Contract, NsId extends keyof TContract['domain']['namespaces']> = EnumEntriesToAccessors<NamespaceEnumEntries<TContract['domain']['namespaces'][NsId]>>
|
|
72
|
+
type NamespaceEnumAccessors<TContract extends Contract, NsId extends keyof TContract['domain']['namespaces']> = keyof BuiltEnumAccessorsOf<TContract> extends never ? EnumEntriesToAccessors<NamespaceEnumEntries<TContract['domain']['namespaces'][NsId]>> : BuiltEnumAccessorsOf<TContract>;
|
|
90
73
|
type NamespacedEnums<TContract extends Contract> = { readonly [Ns in keyof TContract['domain']['namespaces']]: NamespaceEnumAccessors<TContract, Ns> };
|
|
91
74
|
//#endregion
|
|
92
75
|
export { type ContractEnumAccessor, type EnumAccessor, type EnumMemberNames, type EnumValues, type NamespaceEnumAccessors, type NamespacedEnums, buildEnumsMapForNamespace, buildNamespacedEnums, createEnumAccessor };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enum-accessor.d.mts","names":[],"sources":["../src/enum-accessor.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"enum-accessor.d.mts","names":[],"sources":["../src/enum-accessor.ts"],"mappings":";;;;;AAeA;;;;;;;;;UAAiB,YAAA;EAAA,SACN,MAAA,WAAiB,SAAA;EAAA,SACjB,KAAA;EAAA,SACA,OAAA,EAAS,QAAA,CAAS,MAAA,SAAe,SAAA;EAC1C,GAAA,CAAI,CAAA,EAAG,SAAA;EACP,OAAA,CAAQ,IAAA;EACR,MAAA,CAAO,CAAA,EAAG,SAAA;EACV,SAAA,CAAU,CAAA,EAAG,SAAA;AAAA;AAAA,iBAGC,kBAAA,CAAmB,YAAA,EAAc,YAAA,GAAe,YAAY;AAAA,iBAuB5D,yBAAA,CACd,MAAA;EAAA,SACW,UAAA,EAAY,QAAA,CACnB,MAAA;IAAA,SAA0B,IAAA,GAAO,QAAA,CAAS,MAAA,SAAe,YAAA;EAAA;AAAA,GAG7D,WAAA,WACC,MAAA,SAAe,YAAA;AAAA,iBAWF,oBAAA,mBAAuC,QAAA,EACrD,MAAA,EAAQ,SAAA,aACP,eAAA,CAAgB,SAAA;AAAA,KAWd,OAAA,MAAa,OAAO,CAAC,CAAA;AAAA,KAErB,eAAA;EAAA,SAA6B,IAAA;EAAA,SAAuB,KAAA,EAAO,SAAS;AAAA;AAAA,KACpE,SAAA;EAAA,SAAuB,OAAA,WAAkB,eAAe;AAAA;AAAA,KAExD,eAAA,eAA8B,SAAA,2BACZ,KAAA,cAAmB,KAAA,YAAiB,CAAA,UAAW,eAAA,GAChE,KAAA,YAAiB,CAAA;AAAA,KAIlB,cAAA,eAA6B,SAAA,2BACX,KAAA,cAAmB,KAAA,YAAiB,CAAA,UAAW,eAAA,GAChE,KAAA,YAAiB,CAAA;AAAA,KAIlB,gBAAA,eAA+B,SAAA,qBACnB,KAAA,uBAA4B,CAAA,WAAY,CAAA;AAAA,KAG7C,oBAAA,eAAmC,SAAA;EAAA,SACpC,MAAA,EAAQ,eAAA,CAAgB,KAAA;EAAA,SACxB,KAAA,EAAO,cAAA,CAAe,KAAA;EAAA,SACtB,OAAA,EAAS,gBAAA,CAAiB,KAAA,GApDE;EAsDrC,GAAA,CAAI,CAAA,EAAG,SAAA,GAAY,CAAA,IAAK,eAAA,CAAgB,KAAA,WAvDjB;EAyDvB,OAAA,CAAQ,IAAA,WAAe,IAAA,IAAQ,OAAA,CAAQ,cAAA,CAAe,KAAA;EACtD,MAAA,CAAO,CAAA,EAAG,eAAA,CAAgB,KAAA;EAC1B,SAAA,CAAU,CAAA,EAAG,eAAA,CAAgB,KAAA;AAAA;;;;;;KAQnB,UAAA,MAAgB,CAAA;EAAA,SAAqB,MAAA,EAAQ,aAAa;AAAA,IAAc,CAAA;;;;KAKxE,eAAA,MAAqB,CAAA;EAAA,SAAqB,KAAA,EAAO,aAAa;AAAA,IAAc,CAAA;AAAA,KAEnF,sBAAA,iCACkB,KAAA,GAAQ,KAAA,CAAM,CAAA,UAAW,SAAA,GAAY,oBAAA,CAAqB,KAAA,CAAM,CAAA;AAAA,KAGlF,oBAAA,cAAkC,SAAA;EAAA,SAC5B,aAAA;AAAA,IAEP,OAAA,CAAQ,CAAA,eACR,MAAA;AAAA,KAEC,oBAAA,eAAmC,UAAA;EAAA,SAC7B,IAAA;AAAA,oBAES,CAAA,GACd,MAAA,iBACA,OAAA,CAAQ,CAAA,IACV,MAAA;AAAA,KAIQ,sBAAA,mBACQ,QAAA,qBACC,SAAA,kCACX,oBAAA,CAAqB,SAAA,kBAC3B,sBAAA,CAAuB,oBAAA,CAAqB,SAAA,yBAAkC,IAAA,MAC9E,oBAAA,CAAqB,SAAA;AAAA,KAEb,eAAA,mBAAkC,QAAA,4BACtB,SAAA,2BAAoC,sBAAA,CAAuB,SAAA,EAAW,EAAA"}
|
package/dist/enum-accessor.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { blindCast } from "@prisma-next/utils/casts";
|
|
1
2
|
//#region src/enum-accessor.ts
|
|
2
3
|
function createEnumAccessor(contractEnum) {
|
|
3
4
|
const values = Object.freeze(contractEnum.members.map((m) => m.value));
|
|
@@ -17,29 +18,16 @@ function createEnumAccessor(contractEnum) {
|
|
|
17
18
|
ordinalOf: (v) => valueToOrdinal.get(v) ?? -1
|
|
18
19
|
};
|
|
19
20
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Build the enum-accessor map for a single namespace, keyed by enum name.
|
|
22
|
-
* Each namespace facet exposes only its own enums — the IR keys enums under
|
|
23
|
-
* `domain.namespaces[ns].enum`, so the same name in two namespaces resolves
|
|
24
|
-
* independently rather than colliding in one flat map.
|
|
25
|
-
*/
|
|
26
21
|
function buildEnumsMapForNamespace(domain, namespaceId) {
|
|
27
22
|
const result = {};
|
|
28
23
|
const namespace = domain.namespaces[namespaceId];
|
|
29
24
|
if (namespace?.enum) for (const [name, contractEnum] of Object.entries(namespace.enum)) result[name] = createEnumAccessor(contractEnum);
|
|
30
25
|
return result;
|
|
31
26
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Build the enum-accessor map for every namespace of a domain, keyed by
|
|
34
|
-
* namespace id then enum name. This is the lane-agnostic enum surface the
|
|
35
|
-
* `db.enums` facade member exposes: enums are contract metadata, the same
|
|
36
|
-
* whether reached through the sql lane or the orm lane, so the facade builds
|
|
37
|
-
* this once and projects it per target.
|
|
38
|
-
*/
|
|
39
27
|
function buildNamespacedEnums(domain) {
|
|
40
28
|
const result = {};
|
|
41
29
|
for (const namespaceId of Object.keys(domain.namespaces)) result[namespaceId] = buildEnumsMapForNamespace(domain, namespaceId);
|
|
42
|
-
return result;
|
|
30
|
+
return blindCast(result);
|
|
43
31
|
}
|
|
44
32
|
//#endregion
|
|
45
33
|
export { buildEnumsMapForNamespace, buildNamespacedEnums, createEnumAccessor };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enum-accessor.mjs","names":[],"sources":["../src/enum-accessor.ts"],"sourcesContent":["import type { Contract } from './contract-types';\nimport type { ContractEnum } from './domain-types';\nimport type { JsonValue } from './types';\n\n/**\n * Runtime view of a domain enum, built at the client from the emitted\n * `ContractEnum` JSON (codec-encoded `JsonValue` members, literal types erased).\n *\n * This deliberately mirrors the accessor shape of the authoring-time\n * `EnumTypeHandle` (in `contract-ts`) rather than reusing it: that handle carries\n * the literal value generics and lives in the authoring layer, which the\n * foundation layer cannot depend on. The two are the same surface seen from the\n * two planes — authoring (typed) and runtime (validated JSON).\n */\nexport interface EnumAccessor {\n readonly values: readonly JsonValue[];\n readonly names: readonly string[];\n readonly members: Readonly<Record<string, JsonValue>>;\n has(v: JsonValue): boolean;\n hasName(name: string): boolean;\n nameOf(v: JsonValue): string | undefined;\n ordinalOf(v: JsonValue): number;\n}\n\nexport function createEnumAccessor(contractEnum: ContractEnum): EnumAccessor {\n const values = Object.freeze(contractEnum.members.map((m) => m.value));\n const names = Object.freeze(contractEnum.members.map((m) => m.name));\n const members: Readonly<Record<string, JsonValue>> = Object.freeze(\n Object.fromEntries(contractEnum.members.map((m) => [m.name, m.value])),\n );\n\n const valueSet = new Set(values);\n const nameSet = Object.freeze(new Set(names));\n const valueToName = new Map(contractEnum.members.map((m) => [m.value, m.name]));\n const valueToOrdinal = new Map(values.map((v, i) => [v, i]));\n\n return {\n values,\n names,\n members,\n has: (v: JsonValue) => valueSet.has(v),\n hasName: (name: string) => nameSet.has(name),\n nameOf: (v: JsonValue) => valueToName.get(v),\n ordinalOf: (v: JsonValue) => valueToOrdinal.get(v) ?? -1,\n };\n}\n\
|
|
1
|
+
{"version":3,"file":"enum-accessor.mjs","names":[],"sources":["../src/enum-accessor.ts"],"sourcesContent":["import { blindCast } from '@prisma-next/utils/casts';\nimport type { Contract } from './contract-types';\nimport type { ContractEnum } from './domain-types';\nimport type { JsonValue } from './types';\n\n/**\n * Runtime view of a domain enum, built at the client from the emitted\n * `ContractEnum` JSON (codec-encoded `JsonValue` members, literal types erased).\n *\n * This deliberately mirrors the accessor shape of the authoring-time\n * `EnumTypeHandle` (in `contract-ts`) rather than reusing it: that handle carries\n * the literal value generics and lives in the authoring layer, which the\n * foundation layer cannot depend on. The two are the same surface seen from the\n * two planes — authoring (typed) and runtime (validated JSON).\n */\nexport interface EnumAccessor {\n readonly values: readonly JsonValue[];\n readonly names: readonly string[];\n readonly members: Readonly<Record<string, JsonValue>>;\n has(v: JsonValue): boolean;\n hasName(name: string): boolean;\n nameOf(v: JsonValue): string | undefined;\n ordinalOf(v: JsonValue): number;\n}\n\nexport function createEnumAccessor(contractEnum: ContractEnum): EnumAccessor {\n const values = Object.freeze(contractEnum.members.map((m) => m.value));\n const names = Object.freeze(contractEnum.members.map((m) => m.name));\n const members: Readonly<Record<string, JsonValue>> = Object.freeze(\n Object.fromEntries(contractEnum.members.map((m) => [m.name, m.value])),\n );\n\n const valueSet = new Set(values);\n const nameSet = Object.freeze(new Set(names));\n const valueToName = new Map(contractEnum.members.map((m) => [m.value, m.name]));\n const valueToOrdinal = new Map(values.map((v, i) => [v, i]));\n\n return {\n values,\n names,\n members,\n has: (v: JsonValue) => valueSet.has(v),\n hasName: (name: string) => nameSet.has(name),\n nameOf: (v: JsonValue) => valueToName.get(v),\n ordinalOf: (v: JsonValue) => valueToOrdinal.get(v) ?? -1,\n };\n}\n\nexport function buildEnumsMapForNamespace(\n domain: {\n readonly namespaces: Readonly<\n Record<string, { readonly enum?: Readonly<Record<string, ContractEnum>> }>\n >;\n },\n namespaceId: string,\n): Record<string, EnumAccessor> {\n const result: Record<string, EnumAccessor> = {};\n const namespace = domain.namespaces[namespaceId];\n if (namespace?.enum) {\n for (const [name, contractEnum] of Object.entries(namespace.enum)) {\n result[name] = createEnumAccessor(contractEnum);\n }\n }\n return result;\n}\n\nexport function buildNamespacedEnums<TContract extends Contract>(\n domain: TContract['domain'],\n): NamespacedEnums<TContract> {\n const result: Record<string, Record<string, EnumAccessor>> = {};\n for (const namespaceId of Object.keys(domain.namespaces)) {\n result[namespaceId] = buildEnumsMapForNamespace(domain, namespaceId);\n }\n return blindCast<\n NamespacedEnums<TContract>,\n 'built dynamically from domain.namespaces; the mapped-type shape cannot be proven statically'\n >(result);\n}\n\ntype Present<T> = Exclude<T, undefined>;\n\ntype EnumMemberEntry = { readonly name: string; readonly value: JsonValue };\ntype EnumEntry = { readonly members: readonly EnumMemberEntry[] };\n\ntype EnumEntryValues<Entry extends EnumEntry> = {\n readonly [I in keyof Entry['members']]: Entry['members'][I] extends EnumMemberEntry\n ? Entry['members'][I]['value']\n : never;\n};\n\ntype EnumEntryNames<Entry extends EnumEntry> = {\n readonly [I in keyof Entry['members']]: Entry['members'][I] extends EnumMemberEntry\n ? Entry['members'][I]['name']\n : never;\n};\n\ntype EnumEntryMembers<Entry extends EnumEntry> = {\n readonly [M in Entry['members'][number] as M['name']]: M['value'];\n};\n\nexport type ContractEnumAccessor<Entry extends EnumEntry> = {\n readonly values: EnumEntryValues<Entry>;\n readonly names: EnumEntryNames<Entry>;\n readonly members: EnumEntryMembers<Entry>;\n /** Returns true and narrows `v` to the enum's value union when `v` is a declared member value. */\n has(v: JsonValue): v is EnumEntryValues<Entry>[number];\n /** Returns true and narrows `name` to the enum's member-name union when `name` is a declared member name. */\n hasName(name: string): name is Extract<EnumEntryNames<Entry>[number], string>;\n nameOf(v: EnumEntryValues<Entry>[number]): string | undefined;\n ordinalOf(v: EnumEntryValues<Entry>[number]): number;\n};\n\n/**\n * The value union for a `ContractEnumAccessor`.\n * Use in function signatures to accept any declared enum value without re-exporting\n * the member type alias from the accessor's generic entry.\n */\nexport type EnumValues<A> = A extends { readonly values: ReadonlyArray<infer V> } ? V : never;\n\n/**\n * The member-name union for a `ContractEnumAccessor`.\n */\nexport type EnumMemberNames<A> = A extends { readonly names: ReadonlyArray<infer N> } ? N : never;\n\ntype EnumEntriesToAccessors<Enums> = {\n readonly [K in keyof Enums]: Enums[K] extends EnumEntry ? ContractEnumAccessor<Enums[K]> : never;\n};\n\ntype BuiltEnumAccessorsOf<TContract> = TContract extends {\n readonly enumAccessors?: infer A;\n}\n ? Exclude<A, undefined>\n : Record<never, never>;\n\ntype NamespaceEnumEntries<TNamespace> = TNamespace extends {\n readonly enum?: infer E;\n}\n ? unknown extends E\n ? Record<never, never>\n : Present<E>\n : Record<never, never>;\n\n// When `enumAccessors` is present (TS-DSL contract), it is the sole source because merging\n// both carriers would create conflicting `values` types for the same enum key.\nexport type NamespaceEnumAccessors<\n TContract extends Contract,\n NsId extends keyof TContract['domain']['namespaces'],\n> = keyof BuiltEnumAccessorsOf<TContract> extends never\n ? EnumEntriesToAccessors<NamespaceEnumEntries<TContract['domain']['namespaces'][NsId]>>\n : BuiltEnumAccessorsOf<TContract>;\n\nexport type NamespacedEnums<TContract extends Contract> = {\n readonly [Ns in keyof TContract['domain']['namespaces']]: NamespaceEnumAccessors<TContract, Ns>;\n};\n"],"mappings":";;AAyBA,SAAgB,mBAAmB,cAA0C;CAC3E,MAAM,SAAS,OAAO,OAAO,aAAa,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CACrE,MAAM,QAAQ,OAAO,OAAO,aAAa,QAAQ,KAAK,MAAM,EAAE,IAAI,CAAC;CACnE,MAAM,UAA+C,OAAO,OAC1D,OAAO,YAAY,aAAa,QAAQ,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CACvE;CAEA,MAAM,WAAW,IAAI,IAAI,MAAM;CAC/B,MAAM,UAAU,OAAO,OAAO,IAAI,IAAI,KAAK,CAAC;CAC5C,MAAM,cAAc,IAAI,IAAI,aAAa,QAAQ,KAAK,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;CAC9E,MAAM,iBAAiB,IAAI,IAAI,OAAO,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;CAE3D,OAAO;EACL;EACA;EACA;EACA,MAAM,MAAiB,SAAS,IAAI,CAAC;EACrC,UAAU,SAAiB,QAAQ,IAAI,IAAI;EAC3C,SAAS,MAAiB,YAAY,IAAI,CAAC;EAC3C,YAAY,MAAiB,eAAe,IAAI,CAAC,KAAK;CACxD;AACF;AAEA,SAAgB,0BACd,QAKA,aAC8B;CAC9B,MAAM,SAAuC,CAAC;CAC9C,MAAM,YAAY,OAAO,WAAW;CACpC,IAAI,WAAW,MACb,KAAK,MAAM,CAAC,MAAM,iBAAiB,OAAO,QAAQ,UAAU,IAAI,GAC9D,OAAO,QAAQ,mBAAmB,YAAY;CAGlD,OAAO;AACT;AAEA,SAAgB,qBACd,QAC4B;CAC5B,MAAM,SAAuD,CAAC;CAC9D,KAAK,MAAM,eAAe,OAAO,KAAK,OAAO,UAAU,GACrD,OAAO,eAAe,0BAA0B,QAAQ,WAAW;CAErE,OAAO,UAGL,MAAM;AACV"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/contract",
|
|
3
|
-
"version": "0.14.0-dev.
|
|
3
|
+
"version": "0.14.0-dev.31",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "Data contract type definitions and JSON schema for Prisma Next",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/utils": "0.14.0-dev.
|
|
9
|
+
"@prisma-next/utils": "0.14.0-dev.31",
|
|
10
10
|
"@standard-schema/spec": "^1.1.0",
|
|
11
11
|
"arktype": "^2.2.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@prisma-next/tsconfig": "0.14.0-dev.
|
|
15
|
-
"@prisma-next/tsdown": "0.14.0-dev.
|
|
14
|
+
"@prisma-next/tsconfig": "0.14.0-dev.31",
|
|
15
|
+
"@prisma-next/tsdown": "0.14.0-dev.31",
|
|
16
16
|
"tsdown": "0.22.1",
|
|
17
17
|
"typescript": "5.9.3",
|
|
18
18
|
"vitest": "4.1.8"
|
package/src/enum-accessor.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
1
2
|
import type { Contract } from './contract-types';
|
|
2
3
|
import type { ContractEnum } from './domain-types';
|
|
3
4
|
import type { JsonValue } from './types';
|
|
@@ -45,12 +46,6 @@ export function createEnumAccessor(contractEnum: ContractEnum): EnumAccessor {
|
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
/**
|
|
49
|
-
* Build the enum-accessor map for a single namespace, keyed by enum name.
|
|
50
|
-
* Each namespace facet exposes only its own enums — the IR keys enums under
|
|
51
|
-
* `domain.namespaces[ns].enum`, so the same name in two namespaces resolves
|
|
52
|
-
* independently rather than colliding in one flat map.
|
|
53
|
-
*/
|
|
54
49
|
export function buildEnumsMapForNamespace(
|
|
55
50
|
domain: {
|
|
56
51
|
readonly namespaces: Readonly<
|
|
@@ -69,48 +64,21 @@ export function buildEnumsMapForNamespace(
|
|
|
69
64
|
return result;
|
|
70
65
|
}
|
|
71
66
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* `db.enums` facade member exposes: enums are contract metadata, the same
|
|
76
|
-
* whether reached through the sql lane or the orm lane, so the facade builds
|
|
77
|
-
* this once and projects it per target.
|
|
78
|
-
*/
|
|
79
|
-
export function buildNamespacedEnums(domain: {
|
|
80
|
-
readonly namespaces: Readonly<
|
|
81
|
-
Record<string, { readonly enum?: Readonly<Record<string, ContractEnum>> }>
|
|
82
|
-
>;
|
|
83
|
-
}): Record<string, Record<string, EnumAccessor>> {
|
|
67
|
+
export function buildNamespacedEnums<TContract extends Contract>(
|
|
68
|
+
domain: TContract['domain'],
|
|
69
|
+
): NamespacedEnums<TContract> {
|
|
84
70
|
const result: Record<string, Record<string, EnumAccessor>> = {};
|
|
85
71
|
for (const namespaceId of Object.keys(domain.namespaces)) {
|
|
86
72
|
result[namespaceId] = buildEnumsMapForNamespace(domain, namespaceId);
|
|
87
73
|
}
|
|
88
|
-
return
|
|
74
|
+
return blindCast<
|
|
75
|
+
NamespacedEnums<TContract>,
|
|
76
|
+
'built dynamically from domain.namespaces; the mapped-type shape cannot be proven statically'
|
|
77
|
+
>(result);
|
|
89
78
|
}
|
|
90
79
|
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
// Type-level projection of the namespaced enum surface.
|
|
93
|
-
//
|
|
94
|
-
// These types derive the literal-preserving accessor shape from the contract,
|
|
95
|
-
// hung off the `db.enums` facade map (`db.enums.<ns>.<Name>`). They are the
|
|
96
|
-
// same accessors the runtime builds above, but typed from the two emission
|
|
97
|
-
// paths:
|
|
98
|
-
// - Emitted contracts carry the literal enum entries under
|
|
99
|
-
// `domain.namespaces[ns].enum`; each maps to a `ContractEnumAccessor`.
|
|
100
|
-
// - The no-emit (built) contract carries them flat on `enumAccessors`
|
|
101
|
-
// (already accessor-shaped, literal-preserving), since its built domain
|
|
102
|
-
// type does not narrow `namespaces[ns].enum`. All authored enums land in
|
|
103
|
-
// the single built namespace, so exposing the flat map per namespace is
|
|
104
|
-
// correct there.
|
|
105
|
-
// Only `SqlContractResult` carries `enumAccessors`; emitted contracts never
|
|
106
|
-
// do, so the two carriers never overlap.
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
|
|
109
80
|
type Present<T> = Exclude<T, undefined>;
|
|
110
81
|
|
|
111
|
-
// A domain enum entry as carried in `domain.namespaces[ns].enum[name]`: an
|
|
112
|
-
// ordered member tuple. The no-emit (built) path preserves the literal member
|
|
113
|
-
// values so the derived accessor keeps its literal `values`/`names`/`members`.
|
|
114
82
|
type EnumMemberEntry = { readonly name: string; readonly value: JsonValue };
|
|
115
83
|
type EnumEntry = { readonly members: readonly EnumMemberEntry[] };
|
|
116
84
|
|
|
@@ -130,9 +98,6 @@ type EnumEntryMembers<Entry extends EnumEntry> = {
|
|
|
130
98
|
readonly [M in Entry['members'][number] as M['name']]: M['value'];
|
|
131
99
|
};
|
|
132
100
|
|
|
133
|
-
// The runtime accessor shape for one enum, with literal `values`/`names`/
|
|
134
|
-
// `members` derived from the entry's member tuple. Mirrors `EnumAccessor`'s
|
|
135
|
-
// runtime surface and the authoring `EnumTypeHandle` accessor.
|
|
136
101
|
export type ContractEnumAccessor<Entry extends EnumEntry> = {
|
|
137
102
|
readonly values: EnumEntryValues<Entry>;
|
|
138
103
|
readonly names: EnumEntryNames<Entry>;
|
|
@@ -162,9 +127,9 @@ type EnumEntriesToAccessors<Enums> = {
|
|
|
162
127
|
};
|
|
163
128
|
|
|
164
129
|
type BuiltEnumAccessorsOf<TContract> = TContract extends {
|
|
165
|
-
readonly enumAccessors
|
|
130
|
+
readonly enumAccessors?: infer A;
|
|
166
131
|
}
|
|
167
|
-
? A
|
|
132
|
+
? Exclude<A, undefined>
|
|
168
133
|
: Record<never, never>;
|
|
169
134
|
|
|
170
135
|
type NamespaceEnumEntries<TNamespace> = TNamespace extends {
|
|
@@ -175,17 +140,15 @@ type NamespaceEnumEntries<TNamespace> = TNamespace extends {
|
|
|
175
140
|
: Present<E>
|
|
176
141
|
: Record<never, never>;
|
|
177
142
|
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
// namespaces resolves to each namespace's own accessor.
|
|
143
|
+
// When `enumAccessors` is present (TS-DSL contract), it is the sole source because merging
|
|
144
|
+
// both carriers would create conflicting `values` types for the same enum key.
|
|
181
145
|
export type NamespaceEnumAccessors<
|
|
182
146
|
TContract extends Contract,
|
|
183
147
|
NsId extends keyof TContract['domain']['namespaces'],
|
|
184
|
-
> =
|
|
185
|
-
|
|
148
|
+
> = keyof BuiltEnumAccessorsOf<TContract> extends never
|
|
149
|
+
? EnumEntriesToAccessors<NamespaceEnumEntries<TContract['domain']['namespaces'][NsId]>>
|
|
150
|
+
: BuiltEnumAccessorsOf<TContract>;
|
|
186
151
|
|
|
187
|
-
// The lane-agnostic enum surface exposed on the `db.enums` facade member: a
|
|
188
|
-
// namespace-keyed map projected per target exactly like `db.sql` / `db.orm`.
|
|
189
152
|
export type NamespacedEnums<TContract extends Contract> = {
|
|
190
153
|
readonly [Ns in keyof TContract['domain']['namespaces']]: NamespaceEnumAccessors<TContract, Ns>;
|
|
191
154
|
};
|