rotorise 0.1.9 → 0.1.10

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.
@@ -0,0 +1,122 @@
1
+ {
2
+ "src/Rotorise.spec.ts": [
3
+ {
4
+ "location": {
5
+ "start": {
6
+ "line": 199,
7
+ "char": 9
8
+ },
9
+ "end": {
10
+ "line": 199,
11
+ "char": 46
12
+ }
13
+ },
14
+ "args": [
15
+ {
16
+ "type": "({ readonly PK: \"A-a1-B-1-C-true\"; readonly SK: 1; } & { a: \"a1\"; b: 1; c: true; z: \"never\"; }) | ({ readonly PK: \"A-a2-B-2-C-true\"; readonly SK: 2; } & { a: \"a2\"; b: 2; c: true; z: \"never\"; })",
17
+ "relationships": {
18
+ "args": [
19
+ "equality"
20
+ ],
21
+ "typeArgs": [
22
+ "equality"
23
+ ]
24
+ }
25
+ }
26
+ ],
27
+ "typeArgs": [
28
+ {
29
+ "type": "entries",
30
+ "relationships": {
31
+ "args": [
32
+ "equality"
33
+ ],
34
+ "typeArgs": [
35
+ "equality"
36
+ ]
37
+ }
38
+ }
39
+ ],
40
+ "errors": [],
41
+ "completions": {}
42
+ },
43
+ {
44
+ "location": {
45
+ "start": {
46
+ "line": 63,
47
+ "char": 9
48
+ },
49
+ "end": {
50
+ "line": 63,
51
+ "char": 56
52
+ }
53
+ },
54
+ "count": 1911
55
+ },
56
+ {
57
+ "location": {
58
+ "start": {
59
+ "line": 159,
60
+ "char": 9
61
+ },
62
+ "end": {
63
+ "line": 159,
64
+ "char": 56
65
+ }
66
+ },
67
+ "count": 4462
68
+ },
69
+ {
70
+ "location": {
71
+ "start": {
72
+ "line": 312,
73
+ "char": 9
74
+ },
75
+ "end": {
76
+ "line": 312,
77
+ "char": 56
78
+ }
79
+ },
80
+ "count": 11380
81
+ },
82
+ {
83
+ "location": {
84
+ "start": {
85
+ "line": 348,
86
+ "char": 9
87
+ },
88
+ "end": {
89
+ "line": 348,
90
+ "char": 56
91
+ }
92
+ },
93
+ "count": 1401
94
+ },
95
+ {
96
+ "location": {
97
+ "start": {
98
+ "line": 614,
99
+ "char": 9
100
+ },
101
+ "end": {
102
+ "line": 614,
103
+ "char": 57
104
+ }
105
+ },
106
+ "count": 45585
107
+ },
108
+ {
109
+ "location": {
110
+ "start": {
111
+ "line": 830,
112
+ "char": 9
113
+ },
114
+ "end": {
115
+ "line": 830,
116
+ "char": 57
117
+ }
118
+ },
119
+ "count": 40609
120
+ }
121
+ ]
122
+ }
package/dist/Rotorise.cjs CHANGED
@@ -29,7 +29,7 @@ var chainableNoOpProxy = new Proxy(() => chainableNoOpProxy, {
29
29
  var createPathProxy = (path = "") => {
30
30
  return new Proxy(() => {
31
31
  }, {
32
- get: (target, prop, receiver) => {
32
+ get: (target, prop) => {
33
33
  if (typeof prop === "string") {
34
34
  if (prop === "toString") {
35
35
  return () => path;
@@ -78,6 +78,9 @@ var key = () => (schema, separator = "#") => (key2, attributes, config) => {
78
78
  const composite = [];
79
79
  for (const keySpec of structure) {
80
80
  const [key3, transform] = Array.isArray(keySpec) ? keySpec : [keySpec];
81
+ if (key3 === null) {
82
+ continue;
83
+ }
81
84
  const value = attributes[key3];
82
85
  if (value !== void 0 && value !== null && value !== "") {
83
86
  composite.push(key3.toString().toUpperCase());
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["type KeysOfUnion<ObjectType> = ObjectType extends unknown\n ? keyof ObjectType\n : never\ntype IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U\n ? 1\n : 2\n ? true\n : false\n\ntype ArrayElement<T> = T extends readonly unknown[] ? T[0] : never\n\ntype ExactObject<ParameterType, InputType> = {\n [Key in keyof ParameterType]: Exact<\n ParameterType[Key],\n Key extends keyof InputType ? InputType[Key] : never\n >\n} & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>\n\ntype Exact<ParameterType, InputType> = IsEqual<\n ParameterType,\n InputType\n> extends true\n ? ParameterType\n : // Convert union of array to array of union: A[] & B[] => (A & B)[]\n ParameterType extends unknown[]\n ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>\n : // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.\n ParameterType extends readonly unknown[]\n ? ReadonlyArray<\n Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>\n >\n : ParameterType extends object\n ? ExactObject<ParameterType, InputType>\n : ParameterType\n\ntype ValueOf<\n ObjectType,\n ValueType extends keyof ObjectType = keyof ObjectType,\n> = ObjectType[ValueType]\n\nexport type evaluate<T> = T extends unknown\n ? { [K in keyof T]: T[K] } & unknown\n : never\n\ntype SliceFromStart<\n T extends unknown[],\n End extends number,\n Target extends unknown[] = [],\n> = T['length'] | End extends 0\n ? []\n : Target['length'] extends End\n ? Target\n : T extends [infer A, ...infer R]\n ? SliceFromStart<R, End, [...Target, A]>\n : never\n\ntype DistributivePick<T, K> = T extends unknown\n ? K extends keyof T\n ? Pick<T, K>\n : never\n : never\n\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown\n ? Omit<T, K>\n : never\n\ntype Slices<\n rest extends unknown[],\n minLength extends number = 0,\n slice extends unknown[] = [],\n passedSkip extends 1 | 0 = slice['length'] extends minLength ? 1 : 0,\n> =\n | (passedSkip extends 1 ? slice : never)\n | (rest extends [infer h, ...infer R]\n ? Slices<\n R,\n minLength,\n [...slice, h],\n [...slice, h]['length'] extends minLength ? 1 : passedSkip\n >\n : never)\n\nexport type CompositeKeyParams<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n skip extends number = 1,\n P extends InputSpec<Entity>[] = SliceFromStart<\n Spec,\n IsLiteral<skip> extends true ? skip : 1\n >,\n> = Entity extends unknown\n ? P extends unknown\n ? evaluate<\n {\n [K in extractHeadOrPass<P[number]> & string]: Entity[K]\n } & {\n [K in extractHeadOrPass<\n Exclude<Spec[number], P[number]>\n >]?: Entity[K & keyof Entity]\n }\n >\n : never\n : never\ntype IsLiteral<a> = [a] extends [null | undefined]\n ? true\n : [a] extends [string]\n ? string extends a\n ? false\n : true\n : [a] extends [number]\n ? number extends a\n ? false\n : true\n : [a] extends [boolean]\n ? boolean extends a\n ? false\n : true\n : [a] extends [symbol]\n ? symbol extends a\n ? false\n : true\n : [a] extends [bigint]\n ? bigint extends a\n ? false\n : true\n : false\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Delimiter extends string = '#',\n Deep extends number = Spec['length'],\n isPartial extends boolean = false,\n> = Entity extends unknown\n ? CompositeKeyBuilderImpl<\n Entity,\n IsLiteral<Deep> extends true ? SliceFromStart<Spec, Deep> : Spec\n > extends infer Values extends joinablePair[]\n ? Join<\n isPartial & IsLiteral<isPartial> extends false\n ? Values\n : Slices<Values>,\n Delimiter\n >\n : never\n : never\n\ntype joinable = string | number | bigint | boolean | null | undefined\ntype joinablePair = [joinable, joinable]\n\ntype Join<\n Pairs extends joinablePair[],\n Delimiter extends string,\n> = Pairs extends [joinablePair]\n ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}`\n : Pairs extends [joinablePair, ...infer Tail extends joinablePair[]]\n ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}${Delimiter}${Join<\n Tail,\n Delimiter\n >}`\n : never\n\ntype CompositeKeyBuilderImpl<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Pairs extends joinablePair[] = [],\n> = Spec extends [infer F, ...infer R extends InputSpec<Entity>[]]\n ? F extends keyof Entity & string\n ? Entity[F] extends joinable\n ? CompositeKeyBuilderImpl<\n Entity,\n R,\n [...Pairs, [Uppercase<F>, Entity[F]]]\n >\n : never\n : F extends [keyof Entity & string, (...x: (infer _)[]) => infer Tr]\n ? Tr extends joinable\n ? CompositeKeyBuilderImpl<\n Entity,\n R,\n [...Pairs, [Uppercase<F[0]>, Tr]]\n >\n : never\n : never\n : Pairs\n\nexport type TableEntry<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Delimiter extends string = '#',\n> = Entity extends unknown\n ? Entity & {\n [Key in keyof Schema]: Schema[Key] extends keyof Entity\n ? Entity[Schema[Key]]\n : Schema[Key] extends FullKeySpecSimple<Entity>\n ? CompositeKeyBuilder<Entity, Schema[Key], Delimiter>\n : Schema[Key] extends DiscriminatedSchema<Entity>\n ? ValueOf<{\n [K in Schema[Key]['discriminator']]: {\n [V in keyof Schema[Key]['spec']]: Schema[Key]['spec'][V] extends keyof Entity\n ? Extract<\n Entity,\n {\n [k in K]: V\n }\n >[Schema[Key]['spec'][V]]\n : Schema[Key]['spec'][V] extends InputSpec<\n Extract<\n Entity,\n {\n [k in K]: V\n }\n >\n >[]\n ? CompositeKeyBuilder<\n Extract<\n Entity,\n {\n [k in K]: V\n }\n >,\n Schema[Key]['spec'][V],\n Delimiter\n >\n : never\n }[Extract<\n Entity,\n {\n [k in K]: unknown\n }\n >[K] &\n keyof Schema[Key]['spec']]\n }>\n : never\n }\n : never\n\ntype Unionize<T extends object> = {\n [k in keyof T]: { k: k; v: T[k] }\n}[keyof T]\ntype KVPair = { k: PropertyKey; v: unknown }\n\ntype InputSpec<\n Entity extends Record<string, unknown>,\n KV extends KVPair = Unionize<Entity>,\n> = evaluate<\n {\n [key in keyof Entity]:\n | [key, (key: Extract<KV, { k: key }>['v']) => unknown]\n | key\n }[keyof Entity]\n>\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\ntype numeric = number | bigint\ntype keysWithNumericValue<\n Entity extends object,\n KVs extends KVPair = Unionize<Entity>,\n K_wNumber extends PropertyKey = Extract<KVs, { v: numeric }>['k'],\n K_woNumber extends PropertyKey = Exclude<\n KVs,\n { k: K_wNumber; v: numeric }\n >['k'],\n> = Exclude<K_wNumber, K_woNumber>\n\ntype FullKeySpecSimple<Entity extends Record<string, unknown>> =\n | InputSpec<Entity>[]\n | (keysWithNumericValue<Entity> & keyof Entity)\n\ntype entries =\n | { a: 'a1'; b: 1n; c: true; z: '1' }\n | { a: 'a2'; b: 2; c: 0; z: '2' }\n\ntype DiscriminatedSchema<\n Entity extends Record<string, unknown>,\n KVs extends KVPair = Unionize<\n Pick<Entity, keyof Entity> /* Pick common keys */\n >,\n KVs_ extends { k: PropertyKey; v: PropertyKey } = Extract<\n KVs,\n { v: PropertyKey }\n >,\n> = KVs_ extends unknown\n ? {\n discriminator: KVs_['k']\n spec: {\n [val in KVs_['v']]: FullKeySpecSimple<\n Extract<\n Entity,\n {\n [k in KVs_['k']]: val\n }\n >\n > | null\n }\n }\n : never\n\ntype FullKeySpec<Entity extends Record<string, unknown>> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity>\n\ntype t = DiscriminatedSchema<entries>\n\ntype R = ValueOf<{\n [K in t['discriminator']]: evaluate<\n ValueOf<{\n [V in keyof Extract<t, { discriminator: K }>['spec']]: {\n narrow: {\n [k in K]: V\n }\n spec: Extract<\n Extract<t, { discriminator: K }>['spec'],\n { [k in V]: unknown }\n >[V]\n }\n }>\n >\n}>\n\nconst chainableNoOpProxy: unknown = new Proxy(() => chainableNoOpProxy, {\n get: () => chainableNoOpProxy,\n})\n\nconst createPathProxy = <T>(path = ''): T => {\n return new Proxy(() => {}, {\n get: (target, prop, receiver) => {\n if (typeof prop === 'string') {\n if (prop === 'toString') {\n return () => path\n }\n\n return createPathProxy(\n path === ''\n ? prop\n : !Number.isNaN(Number.parseInt(prop))\n ? `${path}[${prop}]`\n : `${path}.${prop}`,\n )\n }\n },\n }) as T\n}\n\nconst key =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity | null\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <\n const Key extends keyof Schema,\n const Config extends { depth?: number; allowPartial?: boolean },\n const Attributes extends Partial<Entity>,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ): string | undefined => {\n const case_ = schema[key]\n\n if (case_ === undefined) {\n throw new Error(`Key ${key.toString()} not found in schema`)\n }\n let structure: InputSpec<Entity>[]\n\n if (Array.isArray(case_)) {\n structure = case_\n } else if (typeof case_ === 'object') {\n const discriminator =\n attributes[case_.discriminator as keyof Attributes]\n if (discriminator === undefined) {\n throw new Error(\n `Discriminator ${case_.discriminator.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n const val = case_.spec[discriminator as keyof typeof case_.spec]\n if (val === undefined) {\n throw new Error(\n `Discriminator value ${discriminator?.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n if (val === null) {\n return undefined\n }\n\n if (!Array.isArray(val)) {\n return attributes[val as keyof Attributes] as never\n }\n\n structure = val\n } else {\n return attributes[case_ as keyof Attributes] as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: string[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n const value = attributes[key as keyof Attributes]\n if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(\n `${transform ? transform(value as never) : value}`,\n )\n } else if (config?.allowPartial) {\n break\n } else {\n throw new Error(\n `buildCompositeKey: Attribute ${key.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n }\n\n return composite.join(separator) as never\n }\n\nconst toEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity | null\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <const ExactEntity extends Entity>(\n item: ExactEntity,\n ): ExactEntity extends infer E extends Entity\n ? Schema extends Record<string, FullKeySpec<E>>\n ? TableEntry<E, Schema, Separator>\n : never\n : never => {\n const entry = { ...item }\n\n for (const key_ in schema) {\n const val = key<Entity>()(schema, separator)(key_, item)\n if (val !== undefined) {\n entry[key_] = val satisfies string as never\n }\n }\n // console.log({ entry })\n return entry as never\n }\n\nconst fromEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n ) =>\n <const Entry extends TableEntry<Entity, Schema, Separator>>(\n entry: Entry,\n ): DistributiveOmit<Entry, keyof Schema> => {\n const item = { ...entry }\n\n for (const key_ in schema) {\n delete item[key_]\n }\n // console.log({ item })\n return item as never\n }\n\ntype TableEntryDefinition<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => ExactEntity extends infer E extends Entity\n ? Schema extends Record<string, FullKeySpec<E>>\n ? TableEntry<E, Schema, Separator>\n : never\n : never\n fromEntry: <const Entry extends TableEntry<Entity, Schema, Separator>>(\n entry: Entry,\n ) => DistributiveOmit<Entry, keyof Schema>\n key: <\n const Key extends string,\n const Config extends IsLiteral<Spec> extends true\n ? never\n : {\n depth?: number\n allowPartial?: boolean\n },\n const Attributes extends IsLiteral<Spec> extends true\n ? DistributivePick<Entity, Spec & keyof Entity>\n : Spec extends InputSpec<Entity>[]\n ? CompositeKeyParams<\n Entity,\n Spec,\n Config['allowPartial'] extends true ? 1 : Spec['length']\n >\n : Spec extends DiscriminatedSchema<Entity>\n ? ValueOf<{\n [K in Spec['discriminator']]: evaluate<\n ValueOf<{\n [V in keyof Extract<\n Spec,\n {\n discriminator: K\n }\n >['spec']]: Entity & {\n [k in K]: V\n } extends infer E extends Record<string, unknown>\n ? Extract<\n Extract<\n Spec,\n {\n discriminator: K\n }\n >['spec'],\n {\n [k in V]: unknown\n }\n >[V] extends infer S\n ? (\n S extends keyof E\n ? DistributivePick<\n E,\n S & keyof E\n >\n : S extends InputSpec<E>[]\n ? CompositeKeyParams<\n E,\n S,\n Config['allowPartial'] extends true\n ? 1\n : S['length']\n >\n : never\n ) extends infer P\n ? [P] extends [never]\n ? {\n [k in K]: V\n }\n : P & {\n [k in K]: V\n }\n : never\n : never\n : never\n }>\n >\n }>\n : never,\n NarrowEntity extends Entity = Entity & Attributes,\n Spec extends FullKeySpec<Entity> = Key extends keyof Schema\n ? Schema[Key]\n : never,\n >(\n key: Key & keyof Schema,\n attributes: Attributes,\n config?: Config,\n ) => Spec extends keyof Entity\n ? ValueOf<Attributes>\n : Spec extends FullKeySpecSimple<NarrowEntity>\n ? CompositeKeyBuilder<\n NarrowEntity,\n Spec,\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec extends DiscriminatedSchema<NarrowEntity>\n ? ValueOf<{\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: Spec['spec'][V] extends keyof NarrowEntity\n ? Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >[Spec['spec'][V]]\n : Spec['spec'][V] extends InputSpec<\n Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >\n >[]\n ? CompositeKeyBuilder<\n Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >,\n Spec['spec'][V],\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec['spec'][V] extends null\n ? undefined\n : never\n }[Extract<\n NarrowEntity,\n {\n [k in K]: unknown\n }\n >[K] &\n keyof Spec['spec']]\n }>\n : never\n infer: TableEntry<Entity, Schema, Separator>\n path: () => TableEntry<Entity, Schema, Separator>\n}\n\nexport const tableEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ): TableEntryDefinition<Entity, Schema, Separator> => {\n return {\n toEntry: toEntry<Entity>()(schema as never, separator) as never,\n fromEntry: fromEntry<Entity>()(schema),\n key: key<Entity>()(schema as never, separator) as never,\n infer: chainableNoOpProxy as TableEntry<Entity, Schema, Separator>,\n path: () =>\n createPathProxy<TableEntry<Entity, Schema, Separator>>(),\n }\n }\n"],"mappings":"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","names":["key"]}
1
+ {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n SliceFromStart,\n UnionToObject,\n ValueOf,\n evaluate,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity extends Record<string, unknown>,\n InputSpec extends InputSpecShape,\n skip extends number = 1,\n> = Entity extends unknown\n ? evaluate<\n Pick<\n Entity,\n extractHeadOrPass<\n SliceFromStart<\n InputSpec,\n number extends skip ? 1 : skip\n >[number]\n > &\n keyof Entity\n > &\n Partial<\n Pick<\n Entity,\n extractHeadOrPass<InputSpec[number]> & keyof Entity\n >\n >\n >\n : never\n\nexport type CompositeKeyParams<\n Entity extends Record<string, unknown>,\n FullSpec extends InputSpec<Entity>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity extends Record<string, unknown>,\n Spec,\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = Entity extends unknown\n ? Join<\n CompositeKeyRec<\n Entity,\n number extends Deep ? Spec : SliceFromStart<Spec, Deep>\n >,\n Separator,\n (boolean extends isPartial ? false : isPartial) extends false\n ? false\n : true\n >\n : never\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>\n\ntype joinable = string | number | bigint | boolean | null | undefined\ntype joinablePair = [joinable, joinable]\n\ntype Join<\n Pairs,\n Separator extends string,\n KeepIntermediate extends boolean = false,\n Acc extends string = '',\n AllAcc extends string = never,\n> = Pairs extends [infer Head extends joinablePair, ...infer Tail]\n ? Join<\n Tail,\n Separator,\n KeepIntermediate,\n Acc extends ''\n ? `${Head[0]}${Separator}${Head[1]}`\n : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`,\n KeepIntermediate extends true\n ? AllAcc | (Acc extends '' ? never : Acc)\n : never\n >\n : AllAcc | Acc\n\ntype ExtractPair<Entity extends Record<string, unknown>, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value extends joinable,\n]\n ? [Uppercase<Key>, Value]\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity extends Record<string, unknown>,\n Spec,\n Acc extends joinablePair[] = [],\n KeysCache extends string = keyof Entity & string,\n> = Spec extends [infer Head, ...infer Tail]\n ? CompositeKeyRec<\n Entity,\n Tail,\n [...Acc, ExtractPair<Entity, Head>],\n KeysCache\n >\n : Acc\n\ntype DiscriminatedSchemaShape = {\n discriminator: PropertyKey\n spec: {\n [k in PropertyKey]: unknown\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\ntype InputSpecShape = ([string, (key: any) => unknown] | string)[]\n\ntype TableEntryImpl<\n Entity extends Record<string, unknown>,\n Schema,\n Separator extends string = '#',\n> = Entity extends unknown\n ? {\n [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape\n ? ValueOf<{\n [K in Schema[Key]['discriminator']]: {\n [V in keyof Schema[Key]['spec']]: ProcessKey<\n Entity,\n Schema[Key]['spec'][V],\n Separator\n >\n }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']]\n }>\n : ProcessKey<Entity, Schema[Key], Separator>\n } & Entity\n : never\n\nexport type TableEntry<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n> = TableEntryImpl<Entity, Schema, Separator>\n\ntype InputSpec<\n Entity extends Record<string, unknown>,\n E extends Record<string, unknown> = UnionToObject<Entity>,\n> = {\n [key in keyof E]: [key, (key: E[key]) => unknown] | key\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity extends Record<string, unknown>> =\n | InputSpec<Entity>[]\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<\n Entity extends Record<string, unknown>,\n E extends Record<string, unknown> = UnionToObject<Entity>,\n> = {\n [key in keyof E]: E[key] extends PropertyKey\n ? {\n discriminator: key\n spec: {\n [val in E[key]]: FullKeySpecSimple<\n Extract<\n Entity,\n {\n [k in key]: val\n }\n >\n >\n }\n }\n : never\n}[keyof E]\n\ntype FullKeySpec<Entity extends Record<string, unknown>> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity>\n\ntype FullKeySpecShape = FullKeySpecSimpleShape | DiscriminatedSchemaShape\n\nconst chainableNoOpProxy: unknown = new Proxy(() => chainableNoOpProxy, {\n get: () => chainableNoOpProxy,\n})\n\nconst createPathProxy = <T>(path = ''): T => {\n return new Proxy(() => {}, {\n get: (target, prop) => {\n if (typeof prop === 'string') {\n if (prop === 'toString') {\n return () => path\n }\n\n return createPathProxy(\n path === ''\n ? prop\n : !Number.isNaN(Number.parseInt(prop))\n ? `${path}[${prop}]`\n : `${path}.${prop}`,\n )\n }\n },\n }) as T\n}\n\nconst key =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <\n const Key extends keyof Schema,\n const Config extends { depth?: number; allowPartial?: boolean },\n const Attributes extends Partial<Entity>,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ): string | undefined => {\n const case_ = schema[key]\n\n if (case_ === undefined) {\n throw new Error(`Key ${key.toString()} not found in schema`)\n }\n let structure: InputSpec<Entity>[]\n\n if (Array.isArray(case_)) {\n structure = case_\n } else if (typeof case_ === 'object') {\n const discriminator =\n attributes[case_.discriminator as keyof Attributes]\n if (discriminator === undefined) {\n throw new Error(\n `Discriminator ${case_.discriminator.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n const val = case_.spec[discriminator as keyof typeof case_.spec]\n if (val === undefined) {\n throw new Error(\n `Discriminator value ${discriminator?.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n if (val === null) {\n return undefined\n }\n\n if (!Array.isArray(val)) {\n return attributes[val as keyof Attributes] as never\n }\n\n structure = val\n } else {\n return attributes[case_ as keyof Attributes] as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: string[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n if (key === null) {\n continue\n }\n\n const value = attributes[key as keyof Attributes]\n if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(\n `${transform ? transform(value as never) : value}`,\n )\n } else if (config?.allowPartial) {\n break\n } else {\n throw new Error(\n `buildCompositeKey: Attribute ${key.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n }\n\n return composite.join(separator) as never\n }\n\nconst toEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <const ExactEntity extends Entity>(\n item: ExactEntity,\n ): ExactEntity extends infer E extends Entity\n ? TableEntryImpl<E, Schema, Separator>\n : never => {\n const entry = { ...item }\n\n for (const key_ in schema) {\n const val = key<Entity>()(schema, separator)(key_, item)\n if (val !== undefined) {\n entry[key_] = val satisfies string as never\n }\n }\n // console.log({ entry })\n return entry as never\n }\n\nconst fromEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpecShape>,\n Separator extends string = '#',\n >(\n schema: Schema,\n ) =>\n <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(\n entry: Entry,\n ): DistributiveOmit<Entry, keyof Schema> => {\n const item = { ...entry }\n\n for (const key_ in schema) {\n delete item[key_]\n }\n // console.log({ item })\n return item as never\n }\n\ntype ProcessSpecType<\n Entity extends Record<string, unknown>,\n Spec,\n Config extends SpecConfigShape,\n> = Spec extends string\n ? DistributivePick<Entity, Spec>\n : Spec extends InputSpecShape\n ? CompositeKeyParamsImpl<\n Entity,\n Spec,\n Config['allowPartial'] extends true\n ? 1\n : Extract<Config['depth'], number>\n >\n : never\n\n// Cache commonly used conditional types\ntype SpecConfig<Spec> = Spec extends string ? never : SpecConfigShape\n\ntype SpecConfigShape = {\n depth?: number\n allowPartial?: boolean\n}\n\n// Pre-compute discriminated variant types\ntype VariantType<Entity, K extends PropertyKey, V extends PropertyKey> = [\n Entity,\n] extends [never]\n ? { [k in K]: V }\n : Entity & { [k in K]: V }\n\n// Flatten nested type computation\ntype ProcessVariant<\n Entity extends Record<string, unknown>,\n K extends PropertyKey,\n V extends PropertyKey,\n Spec extends DiscriminatedSchemaShape,\n Config extends SpecConfigShape,\n> = VariantType<\n ProcessSpecType<\n VariantType<Entity, K, V>,\n Spec['spec'][V & keyof Spec['spec']],\n Config\n >,\n K,\n V\n>\n\n// Optimized attribute processing\ntype OptimizedAttributes<\n Entity extends Record<string, unknown>,\n Spec,\n Config extends SpecConfigShape,\n> = Spec extends DiscriminatedSchemaShape\n ? {\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: ProcessVariant<\n Entity,\n K,\n V,\n Spec,\n Config\n >\n }[keyof Spec['spec']]\n }[Spec['discriminator']]\n : ProcessSpecType<Entity, Spec, Config>\n\ntype ProcessKey<\n Entity extends Record<string, unknown>,\n Spec,\n Separator extends string,\n NullAs extends never | undefined = never,\n Config extends SpecConfigShape = SpecConfigShape,\n Attributes = Pick<Entity, Spec & keyof Entity>,\n> = Spec extends keyof Entity\n ? ValueOf<Attributes>\n : Spec extends InputSpecShape\n ? CompositeKeyBuilderImpl<\n Entity,\n Spec,\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec extends null\n ? NullAs\n : never\n\ntype OptimizedBuildedKey<\n NarrowEntity extends Record<string, unknown>,\n Spec,\n Separator extends string,\n Config extends SpecConfigShape,\n Attributes,\n> = Spec extends DiscriminatedSchemaShape\n ? {\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: ProcessKey<\n NarrowEntity,\n Spec['spec'][V],\n Separator,\n undefined,\n Config,\n Attributes\n >\n }[keyof Spec['spec']]\n }[Spec['discriminator']]\n : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>\n\ntype TableEntryDefinition<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpecShape>,\n Separator extends string,\n> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => ExactEntity extends infer E extends Entity\n ? TableEntryImpl<E, Schema, Separator>\n : never\n fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(\n entry: Entry,\n ) => DistributiveOmit<Entry, keyof Schema>\n key: <\n const Key extends keyof Schema,\n const Config extends SpecConfig<Spec>,\n const Attributes extends OptimizedAttributes<Entity, Spec, Config>,\n Spec = Schema[Key],\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ) => OptimizedBuildedKey<\n Entity & Attributes,\n Spec,\n Separator,\n Config,\n Attributes\n >\n infer: TableEntryImpl<Entity, Schema, Separator>\n path: () => TableEntryImpl<Entity, Schema, Separator>\n}\n\nexport const tableEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ): TableEntryDefinition<Entity, Schema, Separator> => {\n return {\n toEntry: toEntry()(schema as never, separator) as never,\n fromEntry: fromEntry()(schema as never) as never,\n key: key()(schema as never, separator) as never,\n infer: chainableNoOpProxy as never,\n path: () => createPathProxy() as never,\n }\n }\n"],"mappings":"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","names":["key"]}
@@ -1,132 +1,151 @@
1
- type KeysOfUnion<ObjectType> = ObjectType extends unknown ? keyof ObjectType : never;
2
- type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? true : false;
3
- type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
1
+ type KeysOfUnion<ObjectType> = ObjectType extends unknown
2
+ ? keyof ObjectType
3
+ : never
4
+ type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <
5
+ G,
6
+ >() => G extends U ? 1 : 2
7
+ ? true
8
+ : false
9
+
10
+ type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never
11
+
4
12
  type ExactObject<ParameterType, InputType> = {
5
- [Key in keyof ParameterType]: Exact<ParameterType[Key], Key extends keyof InputType ? InputType[Key] : never>;
6
- } & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>;
7
- type Exact<ParameterType, InputType> = IsEqual<ParameterType, InputType> extends true ? ParameterType : ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>> : ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>> : ParameterType extends object ? ExactObject<ParameterType, InputType> : ParameterType;
8
- type ValueOf<ObjectType, ValueType extends keyof ObjectType = keyof ObjectType> = ObjectType[ValueType];
9
- type evaluate<T> = T extends unknown ? {
10
- [K in keyof T]: T[K];
11
- } & unknown : never;
12
- type SliceFromStart<T extends unknown[], End extends number, Target extends unknown[] = []> = T['length'] | End extends 0 ? [] : Target['length'] extends End ? Target : T extends [infer A, ...infer R] ? SliceFromStart<R, End, [...Target, A]> : never;
13
- type DistributivePick<T, K> = T extends unknown ? K extends keyof T ? Pick<T, K> : never : never;
14
- type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
15
- type Slices<rest extends unknown[], minLength extends number = 0, slice extends unknown[] = [], passedSkip extends 1 | 0 = slice['length'] extends minLength ? 1 : 0> = (passedSkip extends 1 ? slice : never) | (rest extends [infer h, ...infer R] ? Slices<R, minLength, [
16
- ...slice,
17
- h
18
- ], [
19
- ...slice,
20
- h
21
- ]['length'] extends minLength ? 1 : passedSkip> : never);
22
- type CompositeKeyParams<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], skip extends number = 1, P extends InputSpec<Entity>[] = SliceFromStart<Spec, IsLiteral<skip> extends true ? skip : 1>> = Entity extends unknown ? P extends unknown ? evaluate<{
23
- [K in extractHeadOrPass<P[number]> & string]: Entity[K];
24
- } & {
25
- [K in extractHeadOrPass<Exclude<Spec[number], P[number]>>]?: Entity[K & keyof Entity];
26
- }> : never : never;
27
- type IsLiteral<a> = [a] extends [null | undefined] ? true : [a] extends [string] ? string extends a ? false : true : [a] extends [number] ? number extends a ? false : true : [a] extends [boolean] ? boolean extends a ? false : true : [a] extends [symbol] ? symbol extends a ? false : true : [a] extends [bigint] ? bigint extends a ? false : true : false;
28
- type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Delimiter extends string = '#', Deep extends number = Spec['length'], isPartial extends boolean = false> = Entity extends unknown ? CompositeKeyBuilderImpl<Entity, IsLiteral<Deep> extends true ? SliceFromStart<Spec, Deep> : Spec> extends infer Values extends joinablePair[] ? Join<isPartial & IsLiteral<isPartial> extends false ? Values : Slices<Values>, Delimiter> : never : never;
13
+ [Key in keyof ParameterType]: Exact<
14
+ ParameterType[Key],
15
+ Key extends keyof InputType ? InputType[Key] : never
16
+ >
17
+ } & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>
18
+
19
+ type Exact<ParameterType, InputType> = IsEqual<
20
+ ParameterType,
21
+ InputType
22
+ > extends true
23
+ ? ParameterType
24
+ : // Convert union of array to array of union: A[] & B[] => (A & B)[]
25
+ ParameterType extends unknown[]
26
+ ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
27
+ : // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
28
+ ParameterType extends readonly unknown[]
29
+ ? ReadonlyArray<
30
+ Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>
31
+ >
32
+ : ParameterType extends object
33
+ ? ExactObject<ParameterType, InputType>
34
+ : ParameterType
35
+
36
+ type ValueOf<
37
+ ObjectType,
38
+ ValueType extends keyof ObjectType = keyof ObjectType,
39
+ > = ObjectType[ValueType]
40
+
41
+ type evaluate<T> = { [K in keyof T]: T[K] } & unknown
42
+
43
+ type DistributivePick<T, K> = T extends unknown
44
+ ? K extends keyof T
45
+ ? Pick<T, K>
46
+ : never
47
+ : never
48
+
49
+ type DistributiveOmit<T, K extends keyof T> = T extends unknown
50
+ ? Omit<T, K>
51
+ : never
52
+
53
+ type SliceFromStart<
54
+ T,
55
+ End extends number,
56
+ Acc extends unknown[] = [],
57
+ > = T extends unknown[]
58
+ ? Acc['length'] extends End
59
+ ? Acc
60
+ : T extends [infer Head, ...infer Tail]
61
+ ? SliceFromStart<Tail, End, [...Acc, Head]>
62
+ : Acc
63
+ : never
64
+
65
+ type UnionToObject<T> = {
66
+ [K in KeysOfUnion<T>]: T extends { [P in K]?: infer U } ? U : never
67
+ }
68
+
69
+ type CompositeKeyParamsImpl<Entity extends Record<string, unknown>, InputSpec extends InputSpecShape, skip extends number = 1> = Entity extends unknown ? evaluate<Pick<Entity, extractHeadOrPass<SliceFromStart<InputSpec, number extends skip ? 1 : skip>[number]> & keyof Entity> & Partial<Pick<Entity, extractHeadOrPass<InputSpec[number]> & keyof Entity>>> : never;
70
+ type CompositeKeyParams<Entity extends Record<string, unknown>, FullSpec extends InputSpec<Entity>[], skip extends number = 1> = CompositeKeyParamsImpl<Entity, FullSpec, skip>;
71
+ type CompositeKeyBuilderImpl<Entity extends Record<string, unknown>, Spec, Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = Entity extends unknown ? Join<CompositeKeyRec<Entity, number extends Deep ? Spec : SliceFromStart<Spec, Deep>>, Separator, (boolean extends isPartial ? false : isPartial) extends false ? false : true> : never;
72
+ type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>;
29
73
  type joinable = string | number | bigint | boolean | null | undefined;
30
74
  type joinablePair = [joinable, joinable];
31
- type Join<Pairs extends joinablePair[], Delimiter extends string> = Pairs extends [joinablePair] ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}` : Pairs extends [joinablePair, ...infer Tail extends joinablePair[]] ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}${Delimiter}${Join<Tail, Delimiter>}` : never;
32
- type CompositeKeyBuilderImpl<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Pairs extends joinablePair[] = []> = Spec extends [infer F, ...infer R extends InputSpec<Entity>[]] ? F extends keyof Entity & string ? Entity[F] extends joinable ? CompositeKeyBuilderImpl<Entity, R, [
33
- ...Pairs,
34
- [Uppercase<F>, Entity[F]]
35
- ]> : never : F extends [keyof Entity & string, (...x: (infer _)[]) => infer Tr] ? Tr extends joinable ? CompositeKeyBuilderImpl<Entity, R, [
36
- ...Pairs,
37
- [Uppercase<F[0]>, Tr]
38
- ]> : never : never : Pairs;
39
- type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Delimiter extends string = '#'> = Entity extends unknown ? Entity & {
40
- [Key in keyof Schema]: Schema[Key] extends keyof Entity ? Entity[Schema[Key]] : Schema[Key] extends FullKeySpecSimple<Entity> ? CompositeKeyBuilder<Entity, Schema[Key], Delimiter> : Schema[Key] extends DiscriminatedSchema<Entity> ? ValueOf<{
41
- [K in Schema[Key]['discriminator']]: {
42
- [V in keyof Schema[Key]['spec']]: Schema[Key]['spec'][V] extends keyof Entity ? Extract<Entity, {
43
- [k in K]: V;
44
- }>[Schema[Key]['spec'][V]] : Schema[Key]['spec'][V] extends InputSpec<Extract<Entity, {
45
- [k in K]: V;
46
- }>>[] ? CompositeKeyBuilder<Extract<Entity, {
47
- [k in K]: V;
48
- }>, Schema[Key]['spec'][V], Delimiter> : never;
49
- }[Extract<Entity, {
50
- [k in K]: unknown;
51
- }>[K] & keyof Schema[Key]['spec']];
52
- }> : never;
53
- } : never;
54
- type Unionize<T extends object> = {
55
- [k in keyof T]: {
56
- k: k;
57
- v: T[k];
75
+ type Join<Pairs, Separator extends string, KeepIntermediate extends boolean = false, Acc extends string = '', AllAcc extends string = never> = Pairs extends [infer Head extends joinablePair, ...infer Tail] ? Join<Tail, Separator, KeepIntermediate, Acc extends '' ? `${Head[0]}${Separator}${Head[1]}` : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`, KeepIntermediate extends true ? AllAcc | (Acc extends '' ? never : Acc) : never> : AllAcc | Acc;
76
+ type ExtractPair<Entity extends Record<string, unknown>, Spec> = Spec extends [
77
+ infer Key extends string,
78
+ (...key: any[]) => infer Value extends joinable
79
+ ] ? [Uppercase<Key>, Value] : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
80
+ type CompositeKeyRec<Entity extends Record<string, unknown>, Spec, Acc extends joinablePair[] = [], KeysCache extends string = keyof Entity & string> = Spec extends [infer Head, ...infer Tail] ? CompositeKeyRec<Entity, Tail, [
81
+ ...Acc,
82
+ ExtractPair<Entity, Head>
83
+ ], KeysCache> : Acc;
84
+ type DiscriminatedSchemaShape = {
85
+ discriminator: PropertyKey;
86
+ spec: {
87
+ [k in PropertyKey]: unknown;
58
88
  };
59
- }[keyof T];
60
- type KVPair = {
61
- k: PropertyKey;
62
- v: unknown;
63
89
  };
64
- type InputSpec<Entity extends Record<string, unknown>, KV extends KVPair = Unionize<Entity>> = evaluate<{
65
- [key in keyof Entity]: [key, (key: Extract<KV, {
66
- k: key;
67
- }>['v']) => unknown] | key;
68
- }[keyof Entity]>;
90
+ type InputSpecShape = ([string, (key: any) => unknown] | string)[];
91
+ type TableEntryImpl<Entity extends Record<string, unknown>, Schema, Separator extends string = '#'> = Entity extends unknown ? {
92
+ [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ValueOf<{
93
+ [K in Schema[Key]['discriminator']]: {
94
+ [V in keyof Schema[Key]['spec']]: ProcessKey<Entity, Schema[Key]['spec'][V], Separator>;
95
+ }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']];
96
+ }> : ProcessKey<Entity, Schema[Key], Separator>;
97
+ } & Entity : never;
98
+ type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = TableEntryImpl<Entity, Schema, Separator>;
99
+ type InputSpec<Entity extends Record<string, unknown>, E extends Record<string, unknown> = UnionToObject<Entity>> = {
100
+ [key in keyof E]: [key, (key: E[key]) => unknown] | key;
101
+ }[keyof E];
69
102
  type extractHeadOrPass<T> = T extends unknown[] ? T[0] : T;
70
- type numeric = number | bigint;
71
- type keysWithNumericValue<Entity extends object, KVs extends KVPair = Unionize<Entity>, K_wNumber extends PropertyKey = Extract<KVs, {
72
- v: numeric;
73
- }>['k'], K_woNumber extends PropertyKey = Exclude<KVs, {
74
- k: K_wNumber;
75
- v: numeric;
76
- }>['k']> = Exclude<K_wNumber, K_woNumber>;
77
- type FullKeySpecSimple<Entity extends Record<string, unknown>> = InputSpec<Entity>[] | (keysWithNumericValue<Entity> & keyof Entity);
78
- type DiscriminatedSchema<Entity extends Record<string, unknown>, KVs extends KVPair = Unionize<Pick<Entity, keyof Entity>>, KVs_ extends {
79
- k: PropertyKey;
80
- v: PropertyKey;
81
- } = Extract<KVs, {
82
- v: PropertyKey;
83
- }>> = KVs_ extends unknown ? {
84
- discriminator: KVs_['k'];
85
- spec: {
86
- [val in KVs_['v']]: FullKeySpecSimple<Extract<Entity, {
87
- [k in KVs_['k']]: val;
88
- }>> | null;
89
- };
90
- } : never;
103
+ type FullKeySpecSimple<Entity extends Record<string, unknown>> = InputSpec<Entity>[] | (keyof Entity & string) | null;
104
+ type FullKeySpecSimpleShape = InputSpecShape | string | null;
105
+ type DiscriminatedSchema<Entity extends Record<string, unknown>, E extends Record<string, unknown> = UnionToObject<Entity>> = {
106
+ [key in keyof E]: E[key] extends PropertyKey ? {
107
+ discriminator: key;
108
+ spec: {
109
+ [val in E[key]]: FullKeySpecSimple<Extract<Entity, {
110
+ [k in key]: val;
111
+ }>>;
112
+ };
113
+ } : never;
114
+ }[keyof E];
91
115
  type FullKeySpec<Entity extends Record<string, unknown>> = FullKeySpecSimple<Entity> | DiscriminatedSchema<Entity>;
92
- type TableEntryDefinition<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = {
93
- toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? Schema extends Record<string, FullKeySpec<E>> ? TableEntry<E, Schema, Separator> : never : never;
94
- fromEntry: <const Entry extends TableEntry<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
95
- key: <const Key extends string, const Config extends IsLiteral<Spec> extends true ? never : {
96
- depth?: number;
97
- allowPartial?: boolean;
98
- }, const Attributes extends IsLiteral<Spec> extends true ? DistributivePick<Entity, Spec & keyof Entity> : Spec extends InputSpec<Entity>[] ? CompositeKeyParams<Entity, Spec, Config['allowPartial'] extends true ? 1 : Spec['length']> : Spec extends DiscriminatedSchema<Entity> ? ValueOf<{
99
- [K in Spec['discriminator']]: evaluate<ValueOf<{
100
- [V in keyof Extract<Spec, {
101
- discriminator: K;
102
- }>['spec']]: Entity & {
103
- [k in K]: V;
104
- } extends infer E extends Record<string, unknown> ? Extract<Extract<Spec, {
105
- discriminator: K;
106
- }>['spec'], {
107
- [k in V]: unknown;
108
- }>[V] extends infer S ? (S extends keyof E ? DistributivePick<E, S & keyof E> : S extends InputSpec<E>[] ? CompositeKeyParams<E, S, Config['allowPartial'] extends true ? 1 : S['length']> : never) extends infer P ? [P] extends [never] ? {
109
- [k in K]: V;
110
- } : P & {
111
- [k in K]: V;
112
- } : never : never : never;
113
- }>>;
114
- }> : never, NarrowEntity extends Entity = Entity & Attributes, Spec extends FullKeySpec<Entity> = Key extends keyof Schema ? Schema[Key] : never>(key: Key & keyof Schema, attributes: Attributes, config?: Config) => Spec extends keyof Entity ? ValueOf<Attributes> : Spec extends FullKeySpecSimple<NarrowEntity> ? CompositeKeyBuilder<NarrowEntity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends DiscriminatedSchema<NarrowEntity> ? ValueOf<{
115
- [K in Spec['discriminator']]: {
116
- [V in keyof Spec['spec']]: Spec['spec'][V] extends keyof NarrowEntity ? Extract<NarrowEntity, {
117
- [k in K]: V;
118
- }>[Spec['spec'][V]] : Spec['spec'][V] extends InputSpec<Extract<NarrowEntity, {
119
- [k in K]: V;
120
- }>>[] ? CompositeKeyBuilder<Extract<NarrowEntity, {
121
- [k in K]: V;
122
- }>, Spec['spec'][V], Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec['spec'][V] extends null ? undefined : never;
123
- }[Extract<NarrowEntity, {
124
- [k in K]: unknown;
125
- }>[K] & keyof Spec['spec']];
126
- }> : never;
127
- infer: TableEntry<Entity, Schema, Separator>;
128
- path: () => TableEntry<Entity, Schema, Separator>;
116
+ type FullKeySpecShape = FullKeySpecSimpleShape | DiscriminatedSchemaShape;
117
+ type ProcessSpecType<Entity extends Record<string, unknown>, Spec, Config extends SpecConfigShape> = Spec extends string ? DistributivePick<Entity, Spec> : Spec extends InputSpecShape ? CompositeKeyParamsImpl<Entity, Spec, Config['allowPartial'] extends true ? 1 : Extract<Config['depth'], number>> : never;
118
+ type SpecConfig<Spec> = Spec extends string ? never : SpecConfigShape;
119
+ type SpecConfigShape = {
120
+ depth?: number;
121
+ allowPartial?: boolean;
122
+ };
123
+ type VariantType<Entity, K extends PropertyKey, V extends PropertyKey> = [
124
+ Entity
125
+ ] extends [never] ? {
126
+ [k in K]: V;
127
+ } : Entity & {
128
+ [k in K]: V;
129
+ };
130
+ type ProcessVariant<Entity extends Record<string, unknown>, K extends PropertyKey, V extends PropertyKey, Spec extends DiscriminatedSchemaShape, Config extends SpecConfigShape> = VariantType<ProcessSpecType<VariantType<Entity, K, V>, Spec['spec'][V & keyof Spec['spec']], Config>, K, V>;
131
+ type OptimizedAttributes<Entity extends Record<string, unknown>, Spec, Config extends SpecConfigShape> = Spec extends DiscriminatedSchemaShape ? {
132
+ [K in Spec['discriminator']]: {
133
+ [V in keyof Spec['spec']]: ProcessVariant<Entity, K, V, Spec, Config>;
134
+ }[keyof Spec['spec']];
135
+ }[Spec['discriminator']] : ProcessSpecType<Entity, Spec, Config>;
136
+ type ProcessKey<Entity extends Record<string, unknown>, Spec, Separator extends string, NullAs extends never | undefined = never, Config extends SpecConfigShape = SpecConfigShape, Attributes = Pick<Entity, Spec & keyof Entity>> = Spec extends keyof Entity ? ValueOf<Attributes> : Spec extends InputSpecShape ? CompositeKeyBuilderImpl<Entity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends null ? NullAs : never;
137
+ type OptimizedBuildedKey<NarrowEntity extends Record<string, unknown>, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Spec extends DiscriminatedSchemaShape ? {
138
+ [K in Spec['discriminator']]: {
139
+ [V in keyof Spec['spec']]: ProcessKey<NarrowEntity, Spec['spec'][V], Separator, undefined, Config, Attributes>;
140
+ }[keyof Spec['spec']];
141
+ }[Spec['discriminator']] : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>;
142
+ type TableEntryDefinition<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpecShape>, Separator extends string> = {
143
+ toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? TableEntryImpl<E, Schema, Separator> : never;
144
+ fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
145
+ key: <const Key extends keyof Schema, const Config extends SpecConfig<Spec>, const Attributes extends OptimizedAttributes<Entity, Spec, Config>, Spec = Schema[Key]>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Entity & Attributes, Spec, Separator, Config, Attributes>;
146
+ infer: TableEntryImpl<Entity, Schema, Separator>;
147
+ path: () => TableEntryImpl<Entity, Schema, Separator>;
129
148
  };
130
149
  declare const tableEntry: <const Entity extends Record<string, unknown>>() => <const Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = "#">(schema: Schema, separator?: Separator) => TableEntryDefinition<Entity, Schema, Separator>;
131
150
 
132
- export { type CompositeKeyBuilder, type CompositeKeyParams, type TableEntry, type evaluate, tableEntry };
151
+ export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, tableEntry };
@@ -1,132 +1,151 @@
1
- type KeysOfUnion<ObjectType> = ObjectType extends unknown ? keyof ObjectType : never;
2
- type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? true : false;
3
- type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
1
+ type KeysOfUnion<ObjectType> = ObjectType extends unknown
2
+ ? keyof ObjectType
3
+ : never
4
+ type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <
5
+ G,
6
+ >() => G extends U ? 1 : 2
7
+ ? true
8
+ : false
9
+
10
+ type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never
11
+
4
12
  type ExactObject<ParameterType, InputType> = {
5
- [Key in keyof ParameterType]: Exact<ParameterType[Key], Key extends keyof InputType ? InputType[Key] : never>;
6
- } & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>;
7
- type Exact<ParameterType, InputType> = IsEqual<ParameterType, InputType> extends true ? ParameterType : ParameterType extends unknown[] ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>> : ParameterType extends readonly unknown[] ? ReadonlyArray<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>> : ParameterType extends object ? ExactObject<ParameterType, InputType> : ParameterType;
8
- type ValueOf<ObjectType, ValueType extends keyof ObjectType = keyof ObjectType> = ObjectType[ValueType];
9
- type evaluate<T> = T extends unknown ? {
10
- [K in keyof T]: T[K];
11
- } & unknown : never;
12
- type SliceFromStart<T extends unknown[], End extends number, Target extends unknown[] = []> = T['length'] | End extends 0 ? [] : Target['length'] extends End ? Target : T extends [infer A, ...infer R] ? SliceFromStart<R, End, [...Target, A]> : never;
13
- type DistributivePick<T, K> = T extends unknown ? K extends keyof T ? Pick<T, K> : never : never;
14
- type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
15
- type Slices<rest extends unknown[], minLength extends number = 0, slice extends unknown[] = [], passedSkip extends 1 | 0 = slice['length'] extends minLength ? 1 : 0> = (passedSkip extends 1 ? slice : never) | (rest extends [infer h, ...infer R] ? Slices<R, minLength, [
16
- ...slice,
17
- h
18
- ], [
19
- ...slice,
20
- h
21
- ]['length'] extends minLength ? 1 : passedSkip> : never);
22
- type CompositeKeyParams<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], skip extends number = 1, P extends InputSpec<Entity>[] = SliceFromStart<Spec, IsLiteral<skip> extends true ? skip : 1>> = Entity extends unknown ? P extends unknown ? evaluate<{
23
- [K in extractHeadOrPass<P[number]> & string]: Entity[K];
24
- } & {
25
- [K in extractHeadOrPass<Exclude<Spec[number], P[number]>>]?: Entity[K & keyof Entity];
26
- }> : never : never;
27
- type IsLiteral<a> = [a] extends [null | undefined] ? true : [a] extends [string] ? string extends a ? false : true : [a] extends [number] ? number extends a ? false : true : [a] extends [boolean] ? boolean extends a ? false : true : [a] extends [symbol] ? symbol extends a ? false : true : [a] extends [bigint] ? bigint extends a ? false : true : false;
28
- type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Delimiter extends string = '#', Deep extends number = Spec['length'], isPartial extends boolean = false> = Entity extends unknown ? CompositeKeyBuilderImpl<Entity, IsLiteral<Deep> extends true ? SliceFromStart<Spec, Deep> : Spec> extends infer Values extends joinablePair[] ? Join<isPartial & IsLiteral<isPartial> extends false ? Values : Slices<Values>, Delimiter> : never : never;
13
+ [Key in keyof ParameterType]: Exact<
14
+ ParameterType[Key],
15
+ Key extends keyof InputType ? InputType[Key] : never
16
+ >
17
+ } & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>
18
+
19
+ type Exact<ParameterType, InputType> = IsEqual<
20
+ ParameterType,
21
+ InputType
22
+ > extends true
23
+ ? ParameterType
24
+ : // Convert union of array to array of union: A[] & B[] => (A & B)[]
25
+ ParameterType extends unknown[]
26
+ ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>
27
+ : // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.
28
+ ParameterType extends readonly unknown[]
29
+ ? ReadonlyArray<
30
+ Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>
31
+ >
32
+ : ParameterType extends object
33
+ ? ExactObject<ParameterType, InputType>
34
+ : ParameterType
35
+
36
+ type ValueOf<
37
+ ObjectType,
38
+ ValueType extends keyof ObjectType = keyof ObjectType,
39
+ > = ObjectType[ValueType]
40
+
41
+ type evaluate<T> = { [K in keyof T]: T[K] } & unknown
42
+
43
+ type DistributivePick<T, K> = T extends unknown
44
+ ? K extends keyof T
45
+ ? Pick<T, K>
46
+ : never
47
+ : never
48
+
49
+ type DistributiveOmit<T, K extends keyof T> = T extends unknown
50
+ ? Omit<T, K>
51
+ : never
52
+
53
+ type SliceFromStart<
54
+ T,
55
+ End extends number,
56
+ Acc extends unknown[] = [],
57
+ > = T extends unknown[]
58
+ ? Acc['length'] extends End
59
+ ? Acc
60
+ : T extends [infer Head, ...infer Tail]
61
+ ? SliceFromStart<Tail, End, [...Acc, Head]>
62
+ : Acc
63
+ : never
64
+
65
+ type UnionToObject<T> = {
66
+ [K in KeysOfUnion<T>]: T extends { [P in K]?: infer U } ? U : never
67
+ }
68
+
69
+ type CompositeKeyParamsImpl<Entity extends Record<string, unknown>, InputSpec extends InputSpecShape, skip extends number = 1> = Entity extends unknown ? evaluate<Pick<Entity, extractHeadOrPass<SliceFromStart<InputSpec, number extends skip ? 1 : skip>[number]> & keyof Entity> & Partial<Pick<Entity, extractHeadOrPass<InputSpec[number]> & keyof Entity>>> : never;
70
+ type CompositeKeyParams<Entity extends Record<string, unknown>, FullSpec extends InputSpec<Entity>[], skip extends number = 1> = CompositeKeyParamsImpl<Entity, FullSpec, skip>;
71
+ type CompositeKeyBuilderImpl<Entity extends Record<string, unknown>, Spec, Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = Entity extends unknown ? Join<CompositeKeyRec<Entity, number extends Deep ? Spec : SliceFromStart<Spec, Deep>>, Separator, (boolean extends isPartial ? false : isPartial) extends false ? false : true> : never;
72
+ type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>;
29
73
  type joinable = string | number | bigint | boolean | null | undefined;
30
74
  type joinablePair = [joinable, joinable];
31
- type Join<Pairs extends joinablePair[], Delimiter extends string> = Pairs extends [joinablePair] ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}` : Pairs extends [joinablePair, ...infer Tail extends joinablePair[]] ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}${Delimiter}${Join<Tail, Delimiter>}` : never;
32
- type CompositeKeyBuilderImpl<Entity extends Record<string, unknown>, Spec extends InputSpec<Entity>[], Pairs extends joinablePair[] = []> = Spec extends [infer F, ...infer R extends InputSpec<Entity>[]] ? F extends keyof Entity & string ? Entity[F] extends joinable ? CompositeKeyBuilderImpl<Entity, R, [
33
- ...Pairs,
34
- [Uppercase<F>, Entity[F]]
35
- ]> : never : F extends [keyof Entity & string, (...x: (infer _)[]) => infer Tr] ? Tr extends joinable ? CompositeKeyBuilderImpl<Entity, R, [
36
- ...Pairs,
37
- [Uppercase<F[0]>, Tr]
38
- ]> : never : never : Pairs;
39
- type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Delimiter extends string = '#'> = Entity extends unknown ? Entity & {
40
- [Key in keyof Schema]: Schema[Key] extends keyof Entity ? Entity[Schema[Key]] : Schema[Key] extends FullKeySpecSimple<Entity> ? CompositeKeyBuilder<Entity, Schema[Key], Delimiter> : Schema[Key] extends DiscriminatedSchema<Entity> ? ValueOf<{
41
- [K in Schema[Key]['discriminator']]: {
42
- [V in keyof Schema[Key]['spec']]: Schema[Key]['spec'][V] extends keyof Entity ? Extract<Entity, {
43
- [k in K]: V;
44
- }>[Schema[Key]['spec'][V]] : Schema[Key]['spec'][V] extends InputSpec<Extract<Entity, {
45
- [k in K]: V;
46
- }>>[] ? CompositeKeyBuilder<Extract<Entity, {
47
- [k in K]: V;
48
- }>, Schema[Key]['spec'][V], Delimiter> : never;
49
- }[Extract<Entity, {
50
- [k in K]: unknown;
51
- }>[K] & keyof Schema[Key]['spec']];
52
- }> : never;
53
- } : never;
54
- type Unionize<T extends object> = {
55
- [k in keyof T]: {
56
- k: k;
57
- v: T[k];
75
+ type Join<Pairs, Separator extends string, KeepIntermediate extends boolean = false, Acc extends string = '', AllAcc extends string = never> = Pairs extends [infer Head extends joinablePair, ...infer Tail] ? Join<Tail, Separator, KeepIntermediate, Acc extends '' ? `${Head[0]}${Separator}${Head[1]}` : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`, KeepIntermediate extends true ? AllAcc | (Acc extends '' ? never : Acc) : never> : AllAcc | Acc;
76
+ type ExtractPair<Entity extends Record<string, unknown>, Spec> = Spec extends [
77
+ infer Key extends string,
78
+ (...key: any[]) => infer Value extends joinable
79
+ ] ? [Uppercase<Key>, Value] : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
80
+ type CompositeKeyRec<Entity extends Record<string, unknown>, Spec, Acc extends joinablePair[] = [], KeysCache extends string = keyof Entity & string> = Spec extends [infer Head, ...infer Tail] ? CompositeKeyRec<Entity, Tail, [
81
+ ...Acc,
82
+ ExtractPair<Entity, Head>
83
+ ], KeysCache> : Acc;
84
+ type DiscriminatedSchemaShape = {
85
+ discriminator: PropertyKey;
86
+ spec: {
87
+ [k in PropertyKey]: unknown;
58
88
  };
59
- }[keyof T];
60
- type KVPair = {
61
- k: PropertyKey;
62
- v: unknown;
63
89
  };
64
- type InputSpec<Entity extends Record<string, unknown>, KV extends KVPair = Unionize<Entity>> = evaluate<{
65
- [key in keyof Entity]: [key, (key: Extract<KV, {
66
- k: key;
67
- }>['v']) => unknown] | key;
68
- }[keyof Entity]>;
90
+ type InputSpecShape = ([string, (key: any) => unknown] | string)[];
91
+ type TableEntryImpl<Entity extends Record<string, unknown>, Schema, Separator extends string = '#'> = Entity extends unknown ? {
92
+ [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ValueOf<{
93
+ [K in Schema[Key]['discriminator']]: {
94
+ [V in keyof Schema[Key]['spec']]: ProcessKey<Entity, Schema[Key]['spec'][V], Separator>;
95
+ }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']];
96
+ }> : ProcessKey<Entity, Schema[Key], Separator>;
97
+ } & Entity : never;
98
+ type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = TableEntryImpl<Entity, Schema, Separator>;
99
+ type InputSpec<Entity extends Record<string, unknown>, E extends Record<string, unknown> = UnionToObject<Entity>> = {
100
+ [key in keyof E]: [key, (key: E[key]) => unknown] | key;
101
+ }[keyof E];
69
102
  type extractHeadOrPass<T> = T extends unknown[] ? T[0] : T;
70
- type numeric = number | bigint;
71
- type keysWithNumericValue<Entity extends object, KVs extends KVPair = Unionize<Entity>, K_wNumber extends PropertyKey = Extract<KVs, {
72
- v: numeric;
73
- }>['k'], K_woNumber extends PropertyKey = Exclude<KVs, {
74
- k: K_wNumber;
75
- v: numeric;
76
- }>['k']> = Exclude<K_wNumber, K_woNumber>;
77
- type FullKeySpecSimple<Entity extends Record<string, unknown>> = InputSpec<Entity>[] | (keysWithNumericValue<Entity> & keyof Entity);
78
- type DiscriminatedSchema<Entity extends Record<string, unknown>, KVs extends KVPair = Unionize<Pick<Entity, keyof Entity>>, KVs_ extends {
79
- k: PropertyKey;
80
- v: PropertyKey;
81
- } = Extract<KVs, {
82
- v: PropertyKey;
83
- }>> = KVs_ extends unknown ? {
84
- discriminator: KVs_['k'];
85
- spec: {
86
- [val in KVs_['v']]: FullKeySpecSimple<Extract<Entity, {
87
- [k in KVs_['k']]: val;
88
- }>> | null;
89
- };
90
- } : never;
103
+ type FullKeySpecSimple<Entity extends Record<string, unknown>> = InputSpec<Entity>[] | (keyof Entity & string) | null;
104
+ type FullKeySpecSimpleShape = InputSpecShape | string | null;
105
+ type DiscriminatedSchema<Entity extends Record<string, unknown>, E extends Record<string, unknown> = UnionToObject<Entity>> = {
106
+ [key in keyof E]: E[key] extends PropertyKey ? {
107
+ discriminator: key;
108
+ spec: {
109
+ [val in E[key]]: FullKeySpecSimple<Extract<Entity, {
110
+ [k in key]: val;
111
+ }>>;
112
+ };
113
+ } : never;
114
+ }[keyof E];
91
115
  type FullKeySpec<Entity extends Record<string, unknown>> = FullKeySpecSimple<Entity> | DiscriminatedSchema<Entity>;
92
- type TableEntryDefinition<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = {
93
- toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? Schema extends Record<string, FullKeySpec<E>> ? TableEntry<E, Schema, Separator> : never : never;
94
- fromEntry: <const Entry extends TableEntry<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
95
- key: <const Key extends string, const Config extends IsLiteral<Spec> extends true ? never : {
96
- depth?: number;
97
- allowPartial?: boolean;
98
- }, const Attributes extends IsLiteral<Spec> extends true ? DistributivePick<Entity, Spec & keyof Entity> : Spec extends InputSpec<Entity>[] ? CompositeKeyParams<Entity, Spec, Config['allowPartial'] extends true ? 1 : Spec['length']> : Spec extends DiscriminatedSchema<Entity> ? ValueOf<{
99
- [K in Spec['discriminator']]: evaluate<ValueOf<{
100
- [V in keyof Extract<Spec, {
101
- discriminator: K;
102
- }>['spec']]: Entity & {
103
- [k in K]: V;
104
- } extends infer E extends Record<string, unknown> ? Extract<Extract<Spec, {
105
- discriminator: K;
106
- }>['spec'], {
107
- [k in V]: unknown;
108
- }>[V] extends infer S ? (S extends keyof E ? DistributivePick<E, S & keyof E> : S extends InputSpec<E>[] ? CompositeKeyParams<E, S, Config['allowPartial'] extends true ? 1 : S['length']> : never) extends infer P ? [P] extends [never] ? {
109
- [k in K]: V;
110
- } : P & {
111
- [k in K]: V;
112
- } : never : never : never;
113
- }>>;
114
- }> : never, NarrowEntity extends Entity = Entity & Attributes, Spec extends FullKeySpec<Entity> = Key extends keyof Schema ? Schema[Key] : never>(key: Key & keyof Schema, attributes: Attributes, config?: Config) => Spec extends keyof Entity ? ValueOf<Attributes> : Spec extends FullKeySpecSimple<NarrowEntity> ? CompositeKeyBuilder<NarrowEntity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends DiscriminatedSchema<NarrowEntity> ? ValueOf<{
115
- [K in Spec['discriminator']]: {
116
- [V in keyof Spec['spec']]: Spec['spec'][V] extends keyof NarrowEntity ? Extract<NarrowEntity, {
117
- [k in K]: V;
118
- }>[Spec['spec'][V]] : Spec['spec'][V] extends InputSpec<Extract<NarrowEntity, {
119
- [k in K]: V;
120
- }>>[] ? CompositeKeyBuilder<Extract<NarrowEntity, {
121
- [k in K]: V;
122
- }>, Spec['spec'][V], Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec['spec'][V] extends null ? undefined : never;
123
- }[Extract<NarrowEntity, {
124
- [k in K]: unknown;
125
- }>[K] & keyof Spec['spec']];
126
- }> : never;
127
- infer: TableEntry<Entity, Schema, Separator>;
128
- path: () => TableEntry<Entity, Schema, Separator>;
116
+ type FullKeySpecShape = FullKeySpecSimpleShape | DiscriminatedSchemaShape;
117
+ type ProcessSpecType<Entity extends Record<string, unknown>, Spec, Config extends SpecConfigShape> = Spec extends string ? DistributivePick<Entity, Spec> : Spec extends InputSpecShape ? CompositeKeyParamsImpl<Entity, Spec, Config['allowPartial'] extends true ? 1 : Extract<Config['depth'], number>> : never;
118
+ type SpecConfig<Spec> = Spec extends string ? never : SpecConfigShape;
119
+ type SpecConfigShape = {
120
+ depth?: number;
121
+ allowPartial?: boolean;
122
+ };
123
+ type VariantType<Entity, K extends PropertyKey, V extends PropertyKey> = [
124
+ Entity
125
+ ] extends [never] ? {
126
+ [k in K]: V;
127
+ } : Entity & {
128
+ [k in K]: V;
129
+ };
130
+ type ProcessVariant<Entity extends Record<string, unknown>, K extends PropertyKey, V extends PropertyKey, Spec extends DiscriminatedSchemaShape, Config extends SpecConfigShape> = VariantType<ProcessSpecType<VariantType<Entity, K, V>, Spec['spec'][V & keyof Spec['spec']], Config>, K, V>;
131
+ type OptimizedAttributes<Entity extends Record<string, unknown>, Spec, Config extends SpecConfigShape> = Spec extends DiscriminatedSchemaShape ? {
132
+ [K in Spec['discriminator']]: {
133
+ [V in keyof Spec['spec']]: ProcessVariant<Entity, K, V, Spec, Config>;
134
+ }[keyof Spec['spec']];
135
+ }[Spec['discriminator']] : ProcessSpecType<Entity, Spec, Config>;
136
+ type ProcessKey<Entity extends Record<string, unknown>, Spec, Separator extends string, NullAs extends never | undefined = never, Config extends SpecConfigShape = SpecConfigShape, Attributes = Pick<Entity, Spec & keyof Entity>> = Spec extends keyof Entity ? ValueOf<Attributes> : Spec extends InputSpecShape ? CompositeKeyBuilderImpl<Entity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends null ? NullAs : never;
137
+ type OptimizedBuildedKey<NarrowEntity extends Record<string, unknown>, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Spec extends DiscriminatedSchemaShape ? {
138
+ [K in Spec['discriminator']]: {
139
+ [V in keyof Spec['spec']]: ProcessKey<NarrowEntity, Spec['spec'][V], Separator, undefined, Config, Attributes>;
140
+ }[keyof Spec['spec']];
141
+ }[Spec['discriminator']] : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>;
142
+ type TableEntryDefinition<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpecShape>, Separator extends string> = {
143
+ toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? TableEntryImpl<E, Schema, Separator> : never;
144
+ fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
145
+ key: <const Key extends keyof Schema, const Config extends SpecConfig<Spec>, const Attributes extends OptimizedAttributes<Entity, Spec, Config>, Spec = Schema[Key]>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Entity & Attributes, Spec, Separator, Config, Attributes>;
146
+ infer: TableEntryImpl<Entity, Schema, Separator>;
147
+ path: () => TableEntryImpl<Entity, Schema, Separator>;
129
148
  };
130
149
  declare const tableEntry: <const Entity extends Record<string, unknown>>() => <const Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = "#">(schema: Schema, separator?: Separator) => TableEntryDefinition<Entity, Schema, Separator>;
131
150
 
132
- export { type CompositeKeyBuilder, type CompositeKeyParams, type TableEntry, type evaluate, tableEntry };
151
+ export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, tableEntry };
package/dist/Rotorise.js CHANGED
@@ -5,7 +5,7 @@ var chainableNoOpProxy = new Proxy(() => chainableNoOpProxy, {
5
5
  var createPathProxy = (path = "") => {
6
6
  return new Proxy(() => {
7
7
  }, {
8
- get: (target, prop, receiver) => {
8
+ get: (target, prop) => {
9
9
  if (typeof prop === "string") {
10
10
  if (prop === "toString") {
11
11
  return () => path;
@@ -54,6 +54,9 @@ var key = () => (schema, separator = "#") => (key2, attributes, config) => {
54
54
  const composite = [];
55
55
  for (const keySpec of structure) {
56
56
  const [key3, transform] = Array.isArray(keySpec) ? keySpec : [keySpec];
57
+ if (key3 === null) {
58
+ continue;
59
+ }
57
60
  const value = attributes[key3];
58
61
  if (value !== void 0 && value !== null && value !== "") {
59
62
  composite.push(key3.toString().toUpperCase());
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["type KeysOfUnion<ObjectType> = ObjectType extends unknown\n ? keyof ObjectType\n : never\ntype IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U\n ? 1\n : 2\n ? true\n : false\n\ntype ArrayElement<T> = T extends readonly unknown[] ? T[0] : never\n\ntype ExactObject<ParameterType, InputType> = {\n [Key in keyof ParameterType]: Exact<\n ParameterType[Key],\n Key extends keyof InputType ? InputType[Key] : never\n >\n} & Record<Exclude<keyof InputType, KeysOfUnion<ParameterType>>, never>\n\ntype Exact<ParameterType, InputType> = IsEqual<\n ParameterType,\n InputType\n> extends true\n ? ParameterType\n : // Convert union of array to array of union: A[] & B[] => (A & B)[]\n ParameterType extends unknown[]\n ? Array<Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>>\n : // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray.\n ParameterType extends readonly unknown[]\n ? ReadonlyArray<\n Exact<ArrayElement<ParameterType>, ArrayElement<InputType>>\n >\n : ParameterType extends object\n ? ExactObject<ParameterType, InputType>\n : ParameterType\n\ntype ValueOf<\n ObjectType,\n ValueType extends keyof ObjectType = keyof ObjectType,\n> = ObjectType[ValueType]\n\nexport type evaluate<T> = T extends unknown\n ? { [K in keyof T]: T[K] } & unknown\n : never\n\ntype SliceFromStart<\n T extends unknown[],\n End extends number,\n Target extends unknown[] = [],\n> = T['length'] | End extends 0\n ? []\n : Target['length'] extends End\n ? Target\n : T extends [infer A, ...infer R]\n ? SliceFromStart<R, End, [...Target, A]>\n : never\n\ntype DistributivePick<T, K> = T extends unknown\n ? K extends keyof T\n ? Pick<T, K>\n : never\n : never\n\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown\n ? Omit<T, K>\n : never\n\ntype Slices<\n rest extends unknown[],\n minLength extends number = 0,\n slice extends unknown[] = [],\n passedSkip extends 1 | 0 = slice['length'] extends minLength ? 1 : 0,\n> =\n | (passedSkip extends 1 ? slice : never)\n | (rest extends [infer h, ...infer R]\n ? Slices<\n R,\n minLength,\n [...slice, h],\n [...slice, h]['length'] extends minLength ? 1 : passedSkip\n >\n : never)\n\nexport type CompositeKeyParams<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n skip extends number = 1,\n P extends InputSpec<Entity>[] = SliceFromStart<\n Spec,\n IsLiteral<skip> extends true ? skip : 1\n >,\n> = Entity extends unknown\n ? P extends unknown\n ? evaluate<\n {\n [K in extractHeadOrPass<P[number]> & string]: Entity[K]\n } & {\n [K in extractHeadOrPass<\n Exclude<Spec[number], P[number]>\n >]?: Entity[K & keyof Entity]\n }\n >\n : never\n : never\ntype IsLiteral<a> = [a] extends [null | undefined]\n ? true\n : [a] extends [string]\n ? string extends a\n ? false\n : true\n : [a] extends [number]\n ? number extends a\n ? false\n : true\n : [a] extends [boolean]\n ? boolean extends a\n ? false\n : true\n : [a] extends [symbol]\n ? symbol extends a\n ? false\n : true\n : [a] extends [bigint]\n ? bigint extends a\n ? false\n : true\n : false\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Delimiter extends string = '#',\n Deep extends number = Spec['length'],\n isPartial extends boolean = false,\n> = Entity extends unknown\n ? CompositeKeyBuilderImpl<\n Entity,\n IsLiteral<Deep> extends true ? SliceFromStart<Spec, Deep> : Spec\n > extends infer Values extends joinablePair[]\n ? Join<\n isPartial & IsLiteral<isPartial> extends false\n ? Values\n : Slices<Values>,\n Delimiter\n >\n : never\n : never\n\ntype joinable = string | number | bigint | boolean | null | undefined\ntype joinablePair = [joinable, joinable]\n\ntype Join<\n Pairs extends joinablePair[],\n Delimiter extends string,\n> = Pairs extends [joinablePair]\n ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}`\n : Pairs extends [joinablePair, ...infer Tail extends joinablePair[]]\n ? `${Pairs[0][0]}${Delimiter}${Pairs[0][1]}${Delimiter}${Join<\n Tail,\n Delimiter\n >}`\n : never\n\ntype CompositeKeyBuilderImpl<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Pairs extends joinablePair[] = [],\n> = Spec extends [infer F, ...infer R extends InputSpec<Entity>[]]\n ? F extends keyof Entity & string\n ? Entity[F] extends joinable\n ? CompositeKeyBuilderImpl<\n Entity,\n R,\n [...Pairs, [Uppercase<F>, Entity[F]]]\n >\n : never\n : F extends [keyof Entity & string, (...x: (infer _)[]) => infer Tr]\n ? Tr extends joinable\n ? CompositeKeyBuilderImpl<\n Entity,\n R,\n [...Pairs, [Uppercase<F[0]>, Tr]]\n >\n : never\n : never\n : Pairs\n\nexport type TableEntry<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Delimiter extends string = '#',\n> = Entity extends unknown\n ? Entity & {\n [Key in keyof Schema]: Schema[Key] extends keyof Entity\n ? Entity[Schema[Key]]\n : Schema[Key] extends FullKeySpecSimple<Entity>\n ? CompositeKeyBuilder<Entity, Schema[Key], Delimiter>\n : Schema[Key] extends DiscriminatedSchema<Entity>\n ? ValueOf<{\n [K in Schema[Key]['discriminator']]: {\n [V in keyof Schema[Key]['spec']]: Schema[Key]['spec'][V] extends keyof Entity\n ? Extract<\n Entity,\n {\n [k in K]: V\n }\n >[Schema[Key]['spec'][V]]\n : Schema[Key]['spec'][V] extends InputSpec<\n Extract<\n Entity,\n {\n [k in K]: V\n }\n >\n >[]\n ? CompositeKeyBuilder<\n Extract<\n Entity,\n {\n [k in K]: V\n }\n >,\n Schema[Key]['spec'][V],\n Delimiter\n >\n : never\n }[Extract<\n Entity,\n {\n [k in K]: unknown\n }\n >[K] &\n keyof Schema[Key]['spec']]\n }>\n : never\n }\n : never\n\ntype Unionize<T extends object> = {\n [k in keyof T]: { k: k; v: T[k] }\n}[keyof T]\ntype KVPair = { k: PropertyKey; v: unknown }\n\ntype InputSpec<\n Entity extends Record<string, unknown>,\n KV extends KVPair = Unionize<Entity>,\n> = evaluate<\n {\n [key in keyof Entity]:\n | [key, (key: Extract<KV, { k: key }>['v']) => unknown]\n | key\n }[keyof Entity]\n>\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\ntype numeric = number | bigint\ntype keysWithNumericValue<\n Entity extends object,\n KVs extends KVPair = Unionize<Entity>,\n K_wNumber extends PropertyKey = Extract<KVs, { v: numeric }>['k'],\n K_woNumber extends PropertyKey = Exclude<\n KVs,\n { k: K_wNumber; v: numeric }\n >['k'],\n> = Exclude<K_wNumber, K_woNumber>\n\ntype FullKeySpecSimple<Entity extends Record<string, unknown>> =\n | InputSpec<Entity>[]\n | (keysWithNumericValue<Entity> & keyof Entity)\n\ntype entries =\n | { a: 'a1'; b: 1n; c: true; z: '1' }\n | { a: 'a2'; b: 2; c: 0; z: '2' }\n\ntype DiscriminatedSchema<\n Entity extends Record<string, unknown>,\n KVs extends KVPair = Unionize<\n Pick<Entity, keyof Entity> /* Pick common keys */\n >,\n KVs_ extends { k: PropertyKey; v: PropertyKey } = Extract<\n KVs,\n { v: PropertyKey }\n >,\n> = KVs_ extends unknown\n ? {\n discriminator: KVs_['k']\n spec: {\n [val in KVs_['v']]: FullKeySpecSimple<\n Extract<\n Entity,\n {\n [k in KVs_['k']]: val\n }\n >\n > | null\n }\n }\n : never\n\ntype FullKeySpec<Entity extends Record<string, unknown>> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity>\n\ntype t = DiscriminatedSchema<entries>\n\ntype R = ValueOf<{\n [K in t['discriminator']]: evaluate<\n ValueOf<{\n [V in keyof Extract<t, { discriminator: K }>['spec']]: {\n narrow: {\n [k in K]: V\n }\n spec: Extract<\n Extract<t, { discriminator: K }>['spec'],\n { [k in V]: unknown }\n >[V]\n }\n }>\n >\n}>\n\nconst chainableNoOpProxy: unknown = new Proxy(() => chainableNoOpProxy, {\n get: () => chainableNoOpProxy,\n})\n\nconst createPathProxy = <T>(path = ''): T => {\n return new Proxy(() => {}, {\n get: (target, prop, receiver) => {\n if (typeof prop === 'string') {\n if (prop === 'toString') {\n return () => path\n }\n\n return createPathProxy(\n path === ''\n ? prop\n : !Number.isNaN(Number.parseInt(prop))\n ? `${path}[${prop}]`\n : `${path}.${prop}`,\n )\n }\n },\n }) as T\n}\n\nconst key =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity | null\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <\n const Key extends keyof Schema,\n const Config extends { depth?: number; allowPartial?: boolean },\n const Attributes extends Partial<Entity>,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ): string | undefined => {\n const case_ = schema[key]\n\n if (case_ === undefined) {\n throw new Error(`Key ${key.toString()} not found in schema`)\n }\n let structure: InputSpec<Entity>[]\n\n if (Array.isArray(case_)) {\n structure = case_\n } else if (typeof case_ === 'object') {\n const discriminator =\n attributes[case_.discriminator as keyof Attributes]\n if (discriminator === undefined) {\n throw new Error(\n `Discriminator ${case_.discriminator.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n const val = case_.spec[discriminator as keyof typeof case_.spec]\n if (val === undefined) {\n throw new Error(\n `Discriminator value ${discriminator?.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n if (val === null) {\n return undefined\n }\n\n if (!Array.isArray(val)) {\n return attributes[val as keyof Attributes] as never\n }\n\n structure = val\n } else {\n return attributes[case_ as keyof Attributes] as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: string[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n const value = attributes[key as keyof Attributes]\n if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(\n `${transform ? transform(value as never) : value}`,\n )\n } else if (config?.allowPartial) {\n break\n } else {\n throw new Error(\n `buildCompositeKey: Attribute ${key.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n }\n\n return composite.join(separator) as never\n }\n\nconst toEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity | null\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <const ExactEntity extends Entity>(\n item: ExactEntity,\n ): ExactEntity extends infer E extends Entity\n ? Schema extends Record<string, FullKeySpec<E>>\n ? TableEntry<E, Schema, Separator>\n : never\n : never => {\n const entry = { ...item }\n\n for (const key_ in schema) {\n const val = key<Entity>()(schema, separator)(key_, item)\n if (val !== undefined) {\n entry[key_] = val satisfies string as never\n }\n }\n // console.log({ entry })\n return entry as never\n }\n\nconst fromEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n ) =>\n <const Entry extends TableEntry<Entity, Schema, Separator>>(\n entry: Entry,\n ): DistributiveOmit<Entry, keyof Schema> => {\n const item = { ...entry }\n\n for (const key_ in schema) {\n delete item[key_]\n }\n // console.log({ item })\n return item as never\n }\n\ntype TableEntryDefinition<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => ExactEntity extends infer E extends Entity\n ? Schema extends Record<string, FullKeySpec<E>>\n ? TableEntry<E, Schema, Separator>\n : never\n : never\n fromEntry: <const Entry extends TableEntry<Entity, Schema, Separator>>(\n entry: Entry,\n ) => DistributiveOmit<Entry, keyof Schema>\n key: <\n const Key extends string,\n const Config extends IsLiteral<Spec> extends true\n ? never\n : {\n depth?: number\n allowPartial?: boolean\n },\n const Attributes extends IsLiteral<Spec> extends true\n ? DistributivePick<Entity, Spec & keyof Entity>\n : Spec extends InputSpec<Entity>[]\n ? CompositeKeyParams<\n Entity,\n Spec,\n Config['allowPartial'] extends true ? 1 : Spec['length']\n >\n : Spec extends DiscriminatedSchema<Entity>\n ? ValueOf<{\n [K in Spec['discriminator']]: evaluate<\n ValueOf<{\n [V in keyof Extract<\n Spec,\n {\n discriminator: K\n }\n >['spec']]: Entity & {\n [k in K]: V\n } extends infer E extends Record<string, unknown>\n ? Extract<\n Extract<\n Spec,\n {\n discriminator: K\n }\n >['spec'],\n {\n [k in V]: unknown\n }\n >[V] extends infer S\n ? (\n S extends keyof E\n ? DistributivePick<\n E,\n S & keyof E\n >\n : S extends InputSpec<E>[]\n ? CompositeKeyParams<\n E,\n S,\n Config['allowPartial'] extends true\n ? 1\n : S['length']\n >\n : never\n ) extends infer P\n ? [P] extends [never]\n ? {\n [k in K]: V\n }\n : P & {\n [k in K]: V\n }\n : never\n : never\n : never\n }>\n >\n }>\n : never,\n NarrowEntity extends Entity = Entity & Attributes,\n Spec extends FullKeySpec<Entity> = Key extends keyof Schema\n ? Schema[Key]\n : never,\n >(\n key: Key & keyof Schema,\n attributes: Attributes,\n config?: Config,\n ) => Spec extends keyof Entity\n ? ValueOf<Attributes>\n : Spec extends FullKeySpecSimple<NarrowEntity>\n ? CompositeKeyBuilder<\n NarrowEntity,\n Spec,\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec extends DiscriminatedSchema<NarrowEntity>\n ? ValueOf<{\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: Spec['spec'][V] extends keyof NarrowEntity\n ? Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >[Spec['spec'][V]]\n : Spec['spec'][V] extends InputSpec<\n Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >\n >[]\n ? CompositeKeyBuilder<\n Extract<\n NarrowEntity,\n {\n [k in K]: V\n }\n >,\n Spec['spec'][V],\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec['spec'][V] extends null\n ? undefined\n : never\n }[Extract<\n NarrowEntity,\n {\n [k in K]: unknown\n }\n >[K] &\n keyof Spec['spec']]\n }>\n : never\n infer: TableEntry<Entity, Schema, Separator>\n path: () => TableEntry<Entity, Schema, Separator>\n}\n\nexport const tableEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ): TableEntryDefinition<Entity, Schema, Separator> => {\n return {\n toEntry: toEntry<Entity>()(schema as never, separator) as never,\n fromEntry: fromEntry<Entity>()(schema),\n key: key<Entity>()(schema as never, separator) as never,\n infer: chainableNoOpProxy as TableEntry<Entity, Schema, Separator>,\n path: () =>\n createPathProxy<TableEntry<Entity, Schema, Separator>>(),\n }\n }\n"],"mappings":"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","names":["key"]}
1
+ {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n SliceFromStart,\n UnionToObject,\n ValueOf,\n evaluate,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity extends Record<string, unknown>,\n InputSpec extends InputSpecShape,\n skip extends number = 1,\n> = Entity extends unknown\n ? evaluate<\n Pick<\n Entity,\n extractHeadOrPass<\n SliceFromStart<\n InputSpec,\n number extends skip ? 1 : skip\n >[number]\n > &\n keyof Entity\n > &\n Partial<\n Pick<\n Entity,\n extractHeadOrPass<InputSpec[number]> & keyof Entity\n >\n >\n >\n : never\n\nexport type CompositeKeyParams<\n Entity extends Record<string, unknown>,\n FullSpec extends InputSpec<Entity>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity extends Record<string, unknown>,\n Spec,\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = Entity extends unknown\n ? Join<\n CompositeKeyRec<\n Entity,\n number extends Deep ? Spec : SliceFromStart<Spec, Deep>\n >,\n Separator,\n (boolean extends isPartial ? false : isPartial) extends false\n ? false\n : true\n >\n : never\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<Entity>[],\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>\n\ntype joinable = string | number | bigint | boolean | null | undefined\ntype joinablePair = [joinable, joinable]\n\ntype Join<\n Pairs,\n Separator extends string,\n KeepIntermediate extends boolean = false,\n Acc extends string = '',\n AllAcc extends string = never,\n> = Pairs extends [infer Head extends joinablePair, ...infer Tail]\n ? Join<\n Tail,\n Separator,\n KeepIntermediate,\n Acc extends ''\n ? `${Head[0]}${Separator}${Head[1]}`\n : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`,\n KeepIntermediate extends true\n ? AllAcc | (Acc extends '' ? never : Acc)\n : never\n >\n : AllAcc | Acc\n\ntype ExtractPair<Entity extends Record<string, unknown>, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value extends joinable,\n]\n ? [Uppercase<Key>, Value]\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity extends Record<string, unknown>,\n Spec,\n Acc extends joinablePair[] = [],\n KeysCache extends string = keyof Entity & string,\n> = Spec extends [infer Head, ...infer Tail]\n ? CompositeKeyRec<\n Entity,\n Tail,\n [...Acc, ExtractPair<Entity, Head>],\n KeysCache\n >\n : Acc\n\ntype DiscriminatedSchemaShape = {\n discriminator: PropertyKey\n spec: {\n [k in PropertyKey]: unknown\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\ntype InputSpecShape = ([string, (key: any) => unknown] | string)[]\n\ntype TableEntryImpl<\n Entity extends Record<string, unknown>,\n Schema,\n Separator extends string = '#',\n> = Entity extends unknown\n ? {\n [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape\n ? ValueOf<{\n [K in Schema[Key]['discriminator']]: {\n [V in keyof Schema[Key]['spec']]: ProcessKey<\n Entity,\n Schema[Key]['spec'][V],\n Separator\n >\n }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']]\n }>\n : ProcessKey<Entity, Schema[Key], Separator>\n } & Entity\n : never\n\nexport type TableEntry<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n> = TableEntryImpl<Entity, Schema, Separator>\n\ntype InputSpec<\n Entity extends Record<string, unknown>,\n E extends Record<string, unknown> = UnionToObject<Entity>,\n> = {\n [key in keyof E]: [key, (key: E[key]) => unknown] | key\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity extends Record<string, unknown>> =\n | InputSpec<Entity>[]\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<\n Entity extends Record<string, unknown>,\n E extends Record<string, unknown> = UnionToObject<Entity>,\n> = {\n [key in keyof E]: E[key] extends PropertyKey\n ? {\n discriminator: key\n spec: {\n [val in E[key]]: FullKeySpecSimple<\n Extract<\n Entity,\n {\n [k in key]: val\n }\n >\n >\n }\n }\n : never\n}[keyof E]\n\ntype FullKeySpec<Entity extends Record<string, unknown>> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity>\n\ntype FullKeySpecShape = FullKeySpecSimpleShape | DiscriminatedSchemaShape\n\nconst chainableNoOpProxy: unknown = new Proxy(() => chainableNoOpProxy, {\n get: () => chainableNoOpProxy,\n})\n\nconst createPathProxy = <T>(path = ''): T => {\n return new Proxy(() => {}, {\n get: (target, prop) => {\n if (typeof prop === 'string') {\n if (prop === 'toString') {\n return () => path\n }\n\n return createPathProxy(\n path === ''\n ? prop\n : !Number.isNaN(Number.parseInt(prop))\n ? `${path}[${prop}]`\n : `${path}.${prop}`,\n )\n }\n },\n }) as T\n}\n\nconst key =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <\n const Key extends keyof Schema,\n const Config extends { depth?: number; allowPartial?: boolean },\n const Attributes extends Partial<Entity>,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ): string | undefined => {\n const case_ = schema[key]\n\n if (case_ === undefined) {\n throw new Error(`Key ${key.toString()} not found in schema`)\n }\n let structure: InputSpec<Entity>[]\n\n if (Array.isArray(case_)) {\n structure = case_\n } else if (typeof case_ === 'object') {\n const discriminator =\n attributes[case_.discriminator as keyof Attributes]\n if (discriminator === undefined) {\n throw new Error(\n `Discriminator ${case_.discriminator.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n const val = case_.spec[discriminator as keyof typeof case_.spec]\n if (val === undefined) {\n throw new Error(\n `Discriminator value ${discriminator?.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n if (val === null) {\n return undefined\n }\n\n if (!Array.isArray(val)) {\n return attributes[val as keyof Attributes] as never\n }\n\n structure = val\n } else {\n return attributes[case_ as keyof Attributes] as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: string[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n if (key === null) {\n continue\n }\n\n const value = attributes[key as keyof Attributes]\n if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(\n `${transform ? transform(value as never) : value}`,\n )\n } else if (config?.allowPartial) {\n break\n } else {\n throw new Error(\n `buildCompositeKey: Attribute ${key.toString()} not found in ${JSON.stringify(attributes)}`,\n )\n }\n }\n\n return composite.join(separator) as never\n }\n\nconst toEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<Entity>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]: InputSpec<Entity>[] | keyof Entity\n }\n }\n >,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ) =>\n <const ExactEntity extends Entity>(\n item: ExactEntity,\n ): ExactEntity extends infer E extends Entity\n ? TableEntryImpl<E, Schema, Separator>\n : never => {\n const entry = { ...item }\n\n for (const key_ in schema) {\n const val = key<Entity>()(schema, separator)(key_, item)\n if (val !== undefined) {\n entry[key_] = val satisfies string as never\n }\n }\n // console.log({ entry })\n return entry as never\n }\n\nconst fromEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpecShape>,\n Separator extends string = '#',\n >(\n schema: Schema,\n ) =>\n <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(\n entry: Entry,\n ): DistributiveOmit<Entry, keyof Schema> => {\n const item = { ...entry }\n\n for (const key_ in schema) {\n delete item[key_]\n }\n // console.log({ item })\n return item as never\n }\n\ntype ProcessSpecType<\n Entity extends Record<string, unknown>,\n Spec,\n Config extends SpecConfigShape,\n> = Spec extends string\n ? DistributivePick<Entity, Spec>\n : Spec extends InputSpecShape\n ? CompositeKeyParamsImpl<\n Entity,\n Spec,\n Config['allowPartial'] extends true\n ? 1\n : Extract<Config['depth'], number>\n >\n : never\n\n// Cache commonly used conditional types\ntype SpecConfig<Spec> = Spec extends string ? never : SpecConfigShape\n\ntype SpecConfigShape = {\n depth?: number\n allowPartial?: boolean\n}\n\n// Pre-compute discriminated variant types\ntype VariantType<Entity, K extends PropertyKey, V extends PropertyKey> = [\n Entity,\n] extends [never]\n ? { [k in K]: V }\n : Entity & { [k in K]: V }\n\n// Flatten nested type computation\ntype ProcessVariant<\n Entity extends Record<string, unknown>,\n K extends PropertyKey,\n V extends PropertyKey,\n Spec extends DiscriminatedSchemaShape,\n Config extends SpecConfigShape,\n> = VariantType<\n ProcessSpecType<\n VariantType<Entity, K, V>,\n Spec['spec'][V & keyof Spec['spec']],\n Config\n >,\n K,\n V\n>\n\n// Optimized attribute processing\ntype OptimizedAttributes<\n Entity extends Record<string, unknown>,\n Spec,\n Config extends SpecConfigShape,\n> = Spec extends DiscriminatedSchemaShape\n ? {\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: ProcessVariant<\n Entity,\n K,\n V,\n Spec,\n Config\n >\n }[keyof Spec['spec']]\n }[Spec['discriminator']]\n : ProcessSpecType<Entity, Spec, Config>\n\ntype ProcessKey<\n Entity extends Record<string, unknown>,\n Spec,\n Separator extends string,\n NullAs extends never | undefined = never,\n Config extends SpecConfigShape = SpecConfigShape,\n Attributes = Pick<Entity, Spec & keyof Entity>,\n> = Spec extends keyof Entity\n ? ValueOf<Attributes>\n : Spec extends InputSpecShape\n ? CompositeKeyBuilderImpl<\n Entity,\n Spec,\n Separator,\n Exclude<Config['depth'], undefined>,\n Exclude<Config['allowPartial'], undefined>\n >\n : Spec extends null\n ? NullAs\n : never\n\ntype OptimizedBuildedKey<\n NarrowEntity extends Record<string, unknown>,\n Spec,\n Separator extends string,\n Config extends SpecConfigShape,\n Attributes,\n> = Spec extends DiscriminatedSchemaShape\n ? {\n [K in Spec['discriminator']]: {\n [V in keyof Spec['spec']]: ProcessKey<\n NarrowEntity,\n Spec['spec'][V],\n Separator,\n undefined,\n Config,\n Attributes\n >\n }[keyof Spec['spec']]\n }[Spec['discriminator']]\n : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>\n\ntype TableEntryDefinition<\n Entity extends Record<string, unknown>,\n Schema extends Record<string, FullKeySpecShape>,\n Separator extends string,\n> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => ExactEntity extends infer E extends Entity\n ? TableEntryImpl<E, Schema, Separator>\n : never\n fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(\n entry: Entry,\n ) => DistributiveOmit<Entry, keyof Schema>\n key: <\n const Key extends keyof Schema,\n const Config extends SpecConfig<Spec>,\n const Attributes extends OptimizedAttributes<Entity, Spec, Config>,\n Spec = Schema[Key],\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ) => OptimizedBuildedKey<\n Entity & Attributes,\n Spec,\n Separator,\n Config,\n Attributes\n >\n infer: TableEntryImpl<Entity, Schema, Separator>\n path: () => TableEntryImpl<Entity, Schema, Separator>\n}\n\nexport const tableEntry =\n <const Entity extends Record<string, unknown>>() =>\n <\n const Schema extends Record<string, FullKeySpec<Entity>>,\n Separator extends string = '#',\n >(\n schema: Schema,\n separator: Separator = '#' as Separator,\n ): TableEntryDefinition<Entity, Schema, Separator> => {\n return {\n toEntry: toEntry()(schema as never, separator) as never,\n fromEntry: fromEntry()(schema as never) as never,\n key: key()(schema as never, separator) as never,\n infer: chainableNoOpProxy as never,\n path: () => createPathProxy() as never,\n }\n }\n"],"mappings":"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","names":["key"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rotorise",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Supercharge your DynamoDB with Rotorise!",
5
5
  "main": "dist/Rotorise.cjs",
6
6
  "types": "dist/Rotorise.d.ts",
@@ -32,8 +32,9 @@
32
32
  "homepage": "https://github.com/josher8a/rotorise",
33
33
  "scripts": {
34
34
  "build": "tsup",
35
- "test": "tsc --noEmit && jest",
36
- "format": "biome format --write ./src"
35
+ "test": "vitest",
36
+ "format": "biome format --write ./src",
37
+ "check": "tsc --noEmit"
37
38
  },
38
39
  "author": {
39
40
  "name": "Joshua Hernandez",
@@ -41,14 +42,12 @@
41
42
  },
42
43
  "license": "Apache-2.0",
43
44
  "devDependencies": {
44
- "@types/jest": "^29.2.2",
45
- "@types/node": "^18.19.34",
45
+ "@ark/attest": "^0.34.0",
46
46
  "@biomejs/biome": "1.8.0",
47
47
  "@swc/jest": "^0.2.36",
48
- "jest": "^29.3.1",
48
+ "@types/node": "^18.19.34",
49
+ "tsup": "^8.1.0",
49
50
  "typescript": "^5.4.5",
50
- "tsup": "^8.1.0"
51
- },
52
- "dependencies": {
51
+ "vitest": "^2.1.8"
53
52
  }
54
- }
53
+ }
package/setupVitest.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { setup } from '@ark/attest'
2
+
3
+ // config options can be passed here
4
+ export default () => setup({})
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globalSetup: ['setupVitest.ts'],
6
+ },
7
+ })