rotorise 0.2.0 → 0.2.3

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.
@@ -3,11 +3,11 @@
3
3
  {
4
4
  "location": {
5
5
  "start": {
6
- "line": 229,
6
+ "line": 252,
7
7
  "char": 9
8
8
  },
9
9
  "end": {
10
- "line": 229,
10
+ "line": 252,
11
11
  "char": 46
12
12
  }
13
13
  },
@@ -43,80 +43,80 @@
43
43
  {
44
44
  "location": {
45
45
  "start": {
46
- "line": 65,
46
+ "line": 61,
47
47
  "char": 9
48
48
  },
49
49
  "end": {
50
- "line": 65,
50
+ "line": 61,
51
51
  "char": 56
52
52
  }
53
53
  },
54
- "count": 2012
54
+ "count": 1906
55
55
  },
56
56
  {
57
57
  "location": {
58
58
  "start": {
59
- "line": 189,
59
+ "line": 212,
60
60
  "char": 9
61
61
  },
62
62
  "end": {
63
- "line": 189,
63
+ "line": 212,
64
64
  "char": 56
65
65
  }
66
66
  },
67
- "count": 5593
67
+ "count": 6883
68
68
  },
69
69
  {
70
70
  "location": {
71
71
  "start": {
72
- "line": 342,
72
+ "line": 365,
73
73
  "char": 9
74
74
  },
75
75
  "end": {
76
- "line": 342,
76
+ "line": 365,
77
77
  "char": 57
78
78
  }
79
79
  },
80
- "count": 11620
80
+ "count": 11244
81
81
  },
82
82
  {
83
83
  "location": {
84
84
  "start": {
85
- "line": 378,
85
+ "line": 401,
86
86
  "char": 9
87
87
  },
88
88
  "end": {
89
- "line": 378,
89
+ "line": 401,
90
90
  "char": 56
91
91
  }
92
92
  },
93
- "count": 1358
93
+ "count": 1396
94
94
  },
95
95
  {
96
96
  "location": {
97
97
  "start": {
98
- "line": 693,
98
+ "line": 717,
99
99
  "char": 9
100
100
  },
101
101
  "end": {
102
- "line": 693,
102
+ "line": 717,
103
103
  "char": 57
104
104
  }
105
105
  },
106
- "count": 65860
106
+ "count": 65118
107
107
  },
108
108
  {
109
109
  "location": {
110
110
  "start": {
111
- "line": 909,
111
+ "line": 933,
112
112
  "char": 9
113
113
  },
114
114
  "end": {
115
- "line": 909,
115
+ "line": 933,
116
116
  "char": 57
117
117
  }
118
118
  },
119
- "count": 48910
119
+ "count": 39094
120
120
  }
121
121
  ]
122
122
  }
package/dist/Rotorise.cjs CHANGED
@@ -79,12 +79,13 @@ var key = () => (schema, separator = "#") => (key2, attributes, config) => {
79
79
  }
80
80
  const composite = [];
81
81
  for (const keySpec of structure) {
82
- const [key3, transform] = Array.isArray(keySpec) ? keySpec : [keySpec];
83
- const value = attributes[key3];
84
- if (transform) {
82
+ const [key3, transform, Default] = Array.isArray(keySpec) ? keySpec : [keySpec];
83
+ const value = attributes[key3] ?? Default;
84
+ if (transform && value !== void 0) {
85
85
  const transformed = transform(value);
86
86
  if (typeof transformed === "object" && transformed !== null) {
87
- composite.push(transformed.tag);
87
+ if (transformed.tag !== void 0)
88
+ composite.push(transformed.tag);
88
89
  composite.push(transformed.value);
89
90
  } else {
90
91
  composite.push(key3.toString().toUpperCase());
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n NonEmptyArray,\n Replace,\n SliceFromStart,\n ValueOf,\n evaluate,\n MergeIntersectionObject,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity,\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<MergeIntersectionObject<Entity>>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity,\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<MergeIntersectionObject<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, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value,\n]\n ? Value extends joinable\n ? [Uppercase<Key>, Value]\n : Value extends {\n tag: infer Tag extends joinable\n value: infer Value extends joinable\n }\n ? [Tag, Value]\n : never\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity,\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 = ([PropertyKey, (key: any) => unknown] | PropertyKey)[]\nexport type TransformShape =\n | {\n tag: string\n value: joinable\n }\n | joinable\n\ntype TableEntryImpl<\n Entity,\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<E> = {\n [key in keyof E]:\n | [key, (key: E[key]) => TransformShape]\n | (undefined extends E[key] ? never : null extends E[key] ? never : key)\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity> =\n | NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>>\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<Entity, E> = {\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> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity, MergeIntersectionObject<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>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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<MergeIntersectionObject<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 const value = attributes[case_ as keyof Attributes]\n if (value == null) return undefined as never\n\n return value as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: joinable[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n\n const value = attributes[key as keyof Attributes]\n\n if (transform) {\n const transformed = transform(value as never)\n if (typeof transformed === 'object' && transformed !== null) {\n composite.push(transformed.tag)\n composite.push(transformed.value)\n } else {\n composite.push(key.toString().toUpperCase())\n composite.push(transformed)\n }\n } else if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(value as joinable)\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<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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,\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,\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,\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,\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> = [Entity] extends [never]\n ? never\n : Spec extends keyof Entity\n ? Replace<ValueOf<Attributes>, null, undefined>\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,\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 extends { [k in K]: V } ? NarrowEntity : never,\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<Entity, Schema, Separator extends string> = {\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 Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] // exclude undefined param\n ? { depth?: undefined; allowPartial?: undefined }\n : Config,\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
+ {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n evaluate,\n MergeIntersectionObject,\n NonEmptyArray,\n Replace,\n SliceFromStart,\n ValueOf,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity,\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<MergeIntersectionObject<Entity>>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity,\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\n >\n : never\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<MergeIntersectionObject<Entity>>[],\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>\n\nexport type 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]] extends [never]\n ? `${Head[1]}`\n : `${Head[0]}${Separator}${Head[1]}`\n : [Head[0]] extends [never]\n ? `${Acc}${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 ExtractHelper<Key, Value> = Value extends joinable\n ? [Key, Value]\n : Value extends {\n tag: infer Tag extends string\n value: infer Value extends joinable\n }\n ? [Tag, Value]\n : Value extends {\n tag?: undefined\n value: infer Value extends joinable\n }\n ? [never, Value]\n : never\n\ntype ExtractPair<Entity, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value,\n ...(infer Default)[],\n]\n ? ExtractHelper<Uppercase<Key>, Value | Default>\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity,\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\ntype InputSpecShape =\n // biome-ignore lint/suspicious/noExplicitAny: ggg\n ([PropertyKey, (key: any) => unknown, ...unknown[]] | PropertyKey)[]\nexport type TransformShape =\n | {\n tag?: string\n value: joinable\n }\n | joinable\n\ntype TableEntryImpl<\n Entity,\n Schema,\n Separator extends string = '#',\n> = Entity extends unknown\n ? {\n [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape\n ? ProcessKey<\n Entity,\n ValueOf<\n Schema[Key]['spec'],\n ValueOf<Entity, Schema[Key]['discriminator']>\n >,\n Separator\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<E> = {\n [key in keyof E]:\n | (undefined extends E[key]\n ? [\n key,\n (key: Exclude<E[key], undefined>) => TransformShape,\n NonNullable<joinable>,\n ]\n : [key, (key: Exclude<E[key], undefined>) => TransformShape])\n | (undefined extends E[key] ? never : null extends E[key] ? never : key)\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends readonly unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity> =\n | NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>>\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<Entity, E> = {\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> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity, MergeIntersectionObject<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>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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<MergeIntersectionObject<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 const value = attributes[case_ as keyof Attributes]\n if (value == null) return undefined as never\n\n return value as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: joinable[] = []\n\n for (const keySpec of structure) {\n const [key, transform, Default] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n\n const value = attributes[key as keyof Attributes] ?? Default\n\n if (transform && value !== undefined) {\n const transformed = transform(value as never)\n if (typeof transformed === 'object' && transformed !== null) {\n if (transformed.tag !== undefined)\n composite.push(transformed.tag)\n composite.push(transformed.value)\n } else {\n composite.push(key.toString().toUpperCase())\n composite.push(transformed)\n }\n } else if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(value as joinable)\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<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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,\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,\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,\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,\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> = [Entity] extends [never]\n ? never\n : Spec extends keyof Entity\n ? Replace<ValueOf<Attributes>, null, undefined>\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 Entity,\n Spec,\n Separator extends string,\n Config extends SpecConfigShape,\n Attributes,\n> = Entity extends unknown\n ? Spec extends DiscriminatedSchemaShape\n ? ProcessKey<\n Entity,\n ValueOf<Spec['spec'], ValueOf<Entity, Spec['discriminator']>>,\n Separator,\n undefined,\n Config,\n Attributes\n >\n : ProcessKey<Entity, Spec, Separator, undefined, Config, Attributes>\n : never\n\ntype TableEntryDefinition<Entity, Schema, Separator extends string> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => TableEntryImpl<ExactEntity, Schema, Separator>\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 Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] // exclude undefined param\n ? { depth?: undefined; allowPartial?: undefined }\n : Config,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ) => OptimizedBuildedKey<Attributes, Spec, Separator, Config_, Attributes>\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"]}
@@ -35,8 +35,8 @@ type Exact<ParameterType, InputType> = IsEqual<
35
35
 
36
36
  type ValueOf<
37
37
  ObjectType,
38
- ValueType extends keyof ObjectType = keyof ObjectType,
39
- > = ObjectType[ValueType]
38
+ ValueType = keyof ObjectType,
39
+ > = ValueType extends keyof ObjectType ? ObjectType[ValueType] : never
40
40
 
41
41
  type evaluate<T> = { [K in keyof T]: T[K] } & unknown
42
42
 
@@ -75,18 +75,23 @@ type Replace<T, U, V> = T extends U ? V : T
75
75
 
76
76
  type CompositeKeyParamsImpl<Entity, 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;
77
77
  type CompositeKeyParams<Entity extends Record<string, unknown>, FullSpec extends InputSpec<MergeIntersectionObject<Entity>>[], skip extends number = 1> = CompositeKeyParamsImpl<Entity, FullSpec, skip>;
78
- type CompositeKeyBuilderImpl<Entity, 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;
78
+ type CompositeKeyBuilderImpl<Entity, 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> : never;
79
79
  type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<MergeIntersectionObject<Entity>>[], Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>;
80
80
  type joinable = string | number | bigint | boolean | null | undefined;
81
81
  type joinablePair = [joinable, joinable];
82
- 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;
82
+ 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]] extends [never] ? `${Head[1]}` : `${Head[0]}${Separator}${Head[1]}` : [Head[0]] extends [never] ? `${Acc}${Separator}${Head[1]}` : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`, KeepIntermediate extends true ? AllAcc | (Acc extends '' ? never : Acc) : never> : AllAcc | Acc;
83
+ type ExtractHelper<Key, Value> = Value extends joinable ? [Key, Value] : Value extends {
84
+ tag: infer Tag extends string;
85
+ value: infer Value extends joinable;
86
+ } ? [Tag, Value] : Value extends {
87
+ tag?: undefined;
88
+ value: infer Value extends joinable;
89
+ } ? [never, Value] : never;
83
90
  type ExtractPair<Entity, Spec> = Spec extends [
84
91
  infer Key extends string,
85
- (...key: any[]) => infer Value
86
- ] ? Value extends joinable ? [Uppercase<Key>, Value] : Value extends {
87
- tag: infer Tag extends joinable;
88
- value: infer Value extends joinable;
89
- } ? [Tag, Value] : never : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
92
+ (...key: any[]) => infer Value,
93
+ ...(infer Default)[]
94
+ ] ? ExtractHelper<Uppercase<Key>, Value | Default> : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
90
95
  type CompositeKeyRec<Entity, Spec, Acc extends joinablePair[] = [], KeysCache extends string = keyof Entity & string> = Spec extends [infer Head, ...infer Tail] ? CompositeKeyRec<Entity, Tail, [
91
96
  ...Acc,
92
97
  ExtractPair<Entity, Head>
@@ -97,23 +102,23 @@ type DiscriminatedSchemaShape = {
97
102
  [k in PropertyKey]: unknown;
98
103
  };
99
104
  };
100
- type InputSpecShape = ([PropertyKey, (key: any) => unknown] | PropertyKey)[];
105
+ type InputSpecShape = ([PropertyKey, (key: any) => unknown, ...unknown[]] | PropertyKey)[];
101
106
  type TransformShape = {
102
- tag: string;
107
+ tag?: string;
103
108
  value: joinable;
104
109
  } | joinable;
105
110
  type TableEntryImpl<Entity, Schema, Separator extends string = '#'> = Entity extends unknown ? {
106
- [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ValueOf<{
107
- [K in Schema[Key]['discriminator']]: {
108
- [V in keyof Schema[Key]['spec']]: ProcessKey<Entity, Schema[Key]['spec'][V], Separator>;
109
- }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']];
110
- }> : ProcessKey<Entity, Schema[Key], Separator>;
111
+ [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ProcessKey<Entity, ValueOf<Schema[Key]['spec'], ValueOf<Entity, Schema[Key]['discriminator']>>, Separator> : ProcessKey<Entity, Schema[Key], Separator>;
111
112
  } & Entity : never;
112
113
  type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = TableEntryImpl<Entity, Schema, Separator>;
113
114
  type InputSpec<E> = {
114
- [key in keyof E]: [key, (key: E[key]) => TransformShape] | (undefined extends E[key] ? never : null extends E[key] ? never : key);
115
+ [key in keyof E]: (undefined extends E[key] ? [
116
+ key,
117
+ (key: Exclude<E[key], undefined>) => TransformShape,
118
+ NonNullable<joinable>
119
+ ] : [key, (key: Exclude<E[key], undefined>) => TransformShape]) | (undefined extends E[key] ? never : null extends E[key] ? never : key);
115
120
  }[keyof E];
116
- type extractHeadOrPass<T> = T extends unknown[] ? T[0] : T;
121
+ type extractHeadOrPass<T> = T extends readonly unknown[] ? T[0] : T;
117
122
  type FullKeySpecSimple<Entity> = NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>> | (keyof Entity & string) | null;
118
123
  type DiscriminatedSchema<Entity, E> = {
119
124
  [key in keyof E]: E[key] extends PropertyKey ? {
@@ -146,23 +151,17 @@ type OptimizedAttributes<Entity, Spec, Config extends SpecConfigShape> = Spec ex
146
151
  }[keyof Spec['spec']];
147
152
  }[Spec['discriminator']] : ProcessSpecType<Entity, Spec, Config>;
148
153
  type ProcessKey<Entity, Spec, Separator extends string, NullAs extends never | undefined = never, Config extends SpecConfigShape = SpecConfigShape, Attributes = Pick<Entity, Spec & keyof Entity>> = [Entity] extends [never] ? never : Spec extends keyof Entity ? Replace<ValueOf<Attributes>, null, undefined> : Spec extends InputSpecShape ? CompositeKeyBuilderImpl<Entity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends null ? NullAs : never;
149
- type OptimizedBuildedKey<NarrowEntity, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Spec extends DiscriminatedSchemaShape ? {
150
- [K in Spec['discriminator']]: {
151
- [V in keyof Spec['spec']]: ProcessKey<NarrowEntity extends {
152
- [k in K]: V;
153
- } ? NarrowEntity : never, Spec['spec'][V], Separator, undefined, Config, Attributes>;
154
- }[keyof Spec['spec']];
155
- }[Spec['discriminator']] : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>;
154
+ type OptimizedBuildedKey<Entity, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Entity extends unknown ? Spec extends DiscriminatedSchemaShape ? ProcessKey<Entity, ValueOf<Spec['spec'], ValueOf<Entity, Spec['discriminator']>>, Separator, undefined, Config, Attributes> : ProcessKey<Entity, Spec, Separator, undefined, Config, Attributes> : never;
156
155
  type TableEntryDefinition<Entity, Schema, Separator extends string> = {
157
- toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? TableEntryImpl<E, Schema, Separator> : never;
156
+ toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => TableEntryImpl<ExactEntity, Schema, Separator>;
158
157
  fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
159
158
  key: <const Key extends keyof Schema, const Config extends SpecConfig<Spec>, const Attributes extends OptimizedAttributes<Entity, Spec, Config_>, Spec = Schema[Key], Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] ? {
160
159
  depth?: undefined;
161
160
  allowPartial?: undefined;
162
- } : Config>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Entity & Attributes, Spec, Separator, Config_, Attributes>;
161
+ } : Config>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Attributes, Spec, Separator, Config_, Attributes>;
163
162
  infer: TableEntryImpl<Entity, Schema, Separator>;
164
163
  path: () => TableEntryImpl<Entity, Schema, Separator>;
165
164
  };
166
165
  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>;
167
166
 
168
- export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, type TransformShape, tableEntry };
167
+ export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, type TransformShape, type joinable, tableEntry };
@@ -35,8 +35,8 @@ type Exact<ParameterType, InputType> = IsEqual<
35
35
 
36
36
  type ValueOf<
37
37
  ObjectType,
38
- ValueType extends keyof ObjectType = keyof ObjectType,
39
- > = ObjectType[ValueType]
38
+ ValueType = keyof ObjectType,
39
+ > = ValueType extends keyof ObjectType ? ObjectType[ValueType] : never
40
40
 
41
41
  type evaluate<T> = { [K in keyof T]: T[K] } & unknown
42
42
 
@@ -75,18 +75,23 @@ type Replace<T, U, V> = T extends U ? V : T
75
75
 
76
76
  type CompositeKeyParamsImpl<Entity, 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;
77
77
  type CompositeKeyParams<Entity extends Record<string, unknown>, FullSpec extends InputSpec<MergeIntersectionObject<Entity>>[], skip extends number = 1> = CompositeKeyParamsImpl<Entity, FullSpec, skip>;
78
- type CompositeKeyBuilderImpl<Entity, 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;
78
+ type CompositeKeyBuilderImpl<Entity, 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> : never;
79
79
  type CompositeKeyBuilder<Entity extends Record<string, unknown>, Spec extends InputSpec<MergeIntersectionObject<Entity>>[], Separator extends string = '#', Deep extends number = number, isPartial extends boolean = false> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>;
80
80
  type joinable = string | number | bigint | boolean | null | undefined;
81
81
  type joinablePair = [joinable, joinable];
82
- 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;
82
+ 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]] extends [never] ? `${Head[1]}` : `${Head[0]}${Separator}${Head[1]}` : [Head[0]] extends [never] ? `${Acc}${Separator}${Head[1]}` : `${Acc}${Separator}${Head[0]}${Separator}${Head[1]}`, KeepIntermediate extends true ? AllAcc | (Acc extends '' ? never : Acc) : never> : AllAcc | Acc;
83
+ type ExtractHelper<Key, Value> = Value extends joinable ? [Key, Value] : Value extends {
84
+ tag: infer Tag extends string;
85
+ value: infer Value extends joinable;
86
+ } ? [Tag, Value] : Value extends {
87
+ tag?: undefined;
88
+ value: infer Value extends joinable;
89
+ } ? [never, Value] : never;
83
90
  type ExtractPair<Entity, Spec> = Spec extends [
84
91
  infer Key extends string,
85
- (...key: any[]) => infer Value
86
- ] ? Value extends joinable ? [Uppercase<Key>, Value] : Value extends {
87
- tag: infer Tag extends joinable;
88
- value: infer Value extends joinable;
89
- } ? [Tag, Value] : never : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
92
+ (...key: any[]) => infer Value,
93
+ ...(infer Default)[]
94
+ ] ? ExtractHelper<Uppercase<Key>, Value | Default> : Spec extends keyof Entity & string ? [Uppercase<Spec>, Entity[Spec] & joinable] : never;
90
95
  type CompositeKeyRec<Entity, Spec, Acc extends joinablePair[] = [], KeysCache extends string = keyof Entity & string> = Spec extends [infer Head, ...infer Tail] ? CompositeKeyRec<Entity, Tail, [
91
96
  ...Acc,
92
97
  ExtractPair<Entity, Head>
@@ -97,23 +102,23 @@ type DiscriminatedSchemaShape = {
97
102
  [k in PropertyKey]: unknown;
98
103
  };
99
104
  };
100
- type InputSpecShape = ([PropertyKey, (key: any) => unknown] | PropertyKey)[];
105
+ type InputSpecShape = ([PropertyKey, (key: any) => unknown, ...unknown[]] | PropertyKey)[];
101
106
  type TransformShape = {
102
- tag: string;
107
+ tag?: string;
103
108
  value: joinable;
104
109
  } | joinable;
105
110
  type TableEntryImpl<Entity, Schema, Separator extends string = '#'> = Entity extends unknown ? {
106
- [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ValueOf<{
107
- [K in Schema[Key]['discriminator']]: {
108
- [V in keyof Schema[Key]['spec']]: ProcessKey<Entity, Schema[Key]['spec'][V], Separator>;
109
- }[Entity[K & keyof Entity] & keyof Schema[Key]['spec']];
110
- }> : ProcessKey<Entity, Schema[Key], Separator>;
111
+ [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape ? ProcessKey<Entity, ValueOf<Schema[Key]['spec'], ValueOf<Entity, Schema[Key]['discriminator']>>, Separator> : ProcessKey<Entity, Schema[Key], Separator>;
111
112
  } & Entity : never;
112
113
  type TableEntry<Entity extends Record<string, unknown>, Schema extends Record<string, FullKeySpec<Entity>>, Separator extends string = '#'> = TableEntryImpl<Entity, Schema, Separator>;
113
114
  type InputSpec<E> = {
114
- [key in keyof E]: [key, (key: E[key]) => TransformShape] | (undefined extends E[key] ? never : null extends E[key] ? never : key);
115
+ [key in keyof E]: (undefined extends E[key] ? [
116
+ key,
117
+ (key: Exclude<E[key], undefined>) => TransformShape,
118
+ NonNullable<joinable>
119
+ ] : [key, (key: Exclude<E[key], undefined>) => TransformShape]) | (undefined extends E[key] ? never : null extends E[key] ? never : key);
115
120
  }[keyof E];
116
- type extractHeadOrPass<T> = T extends unknown[] ? T[0] : T;
121
+ type extractHeadOrPass<T> = T extends readonly unknown[] ? T[0] : T;
117
122
  type FullKeySpecSimple<Entity> = NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>> | (keyof Entity & string) | null;
118
123
  type DiscriminatedSchema<Entity, E> = {
119
124
  [key in keyof E]: E[key] extends PropertyKey ? {
@@ -146,23 +151,17 @@ type OptimizedAttributes<Entity, Spec, Config extends SpecConfigShape> = Spec ex
146
151
  }[keyof Spec['spec']];
147
152
  }[Spec['discriminator']] : ProcessSpecType<Entity, Spec, Config>;
148
153
  type ProcessKey<Entity, Spec, Separator extends string, NullAs extends never | undefined = never, Config extends SpecConfigShape = SpecConfigShape, Attributes = Pick<Entity, Spec & keyof Entity>> = [Entity] extends [never] ? never : Spec extends keyof Entity ? Replace<ValueOf<Attributes>, null, undefined> : Spec extends InputSpecShape ? CompositeKeyBuilderImpl<Entity, Spec, Separator, Exclude<Config['depth'], undefined>, Exclude<Config['allowPartial'], undefined>> : Spec extends null ? NullAs : never;
149
- type OptimizedBuildedKey<NarrowEntity, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Spec extends DiscriminatedSchemaShape ? {
150
- [K in Spec['discriminator']]: {
151
- [V in keyof Spec['spec']]: ProcessKey<NarrowEntity extends {
152
- [k in K]: V;
153
- } ? NarrowEntity : never, Spec['spec'][V], Separator, undefined, Config, Attributes>;
154
- }[keyof Spec['spec']];
155
- }[Spec['discriminator']] : ProcessKey<NarrowEntity, Spec, Separator, undefined, Config, Attributes>;
154
+ type OptimizedBuildedKey<Entity, Spec, Separator extends string, Config extends SpecConfigShape, Attributes> = Entity extends unknown ? Spec extends DiscriminatedSchemaShape ? ProcessKey<Entity, ValueOf<Spec['spec'], ValueOf<Entity, Spec['discriminator']>>, Separator, undefined, Config, Attributes> : ProcessKey<Entity, Spec, Separator, undefined, Config, Attributes> : never;
156
155
  type TableEntryDefinition<Entity, Schema, Separator extends string> = {
157
- toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => ExactEntity extends infer E extends Entity ? TableEntryImpl<E, Schema, Separator> : never;
156
+ toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(item: ExactEntity) => TableEntryImpl<ExactEntity, Schema, Separator>;
158
157
  fromEntry: <const Entry extends TableEntryImpl<Entity, Schema, Separator>>(entry: Entry) => DistributiveOmit<Entry, keyof Schema>;
159
158
  key: <const Key extends keyof Schema, const Config extends SpecConfig<Spec>, const Attributes extends OptimizedAttributes<Entity, Spec, Config_>, Spec = Schema[Key], Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] ? {
160
159
  depth?: undefined;
161
160
  allowPartial?: undefined;
162
- } : Config>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Entity & Attributes, Spec, Separator, Config_, Attributes>;
161
+ } : Config>(key: Key, attributes: Attributes, config?: Config) => OptimizedBuildedKey<Attributes, Spec, Separator, Config_, Attributes>;
163
162
  infer: TableEntryImpl<Entity, Schema, Separator>;
164
163
  path: () => TableEntryImpl<Entity, Schema, Separator>;
165
164
  };
166
165
  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>;
167
166
 
168
- export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, type TransformShape, tableEntry };
167
+ export { type CompositeKeyBuilder, type CompositeKeyParams, type CompositeKeyParamsImpl, type TableEntry, type TransformShape, type joinable, tableEntry };
package/dist/Rotorise.js CHANGED
@@ -55,12 +55,13 @@ var key = () => (schema, separator = "#") => (key2, attributes, config) => {
55
55
  }
56
56
  const composite = [];
57
57
  for (const keySpec of structure) {
58
- const [key3, transform] = Array.isArray(keySpec) ? keySpec : [keySpec];
59
- const value = attributes[key3];
60
- if (transform) {
58
+ const [key3, transform, Default] = Array.isArray(keySpec) ? keySpec : [keySpec];
59
+ const value = attributes[key3] ?? Default;
60
+ if (transform && value !== void 0) {
61
61
  const transformed = transform(value);
62
62
  if (typeof transformed === "object" && transformed !== null) {
63
- composite.push(transformed.tag);
63
+ if (transformed.tag !== void 0)
64
+ composite.push(transformed.tag);
64
65
  composite.push(transformed.value);
65
66
  } else {
66
67
  composite.push(key3.toString().toUpperCase());
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n NonEmptyArray,\n Replace,\n SliceFromStart,\n ValueOf,\n evaluate,\n MergeIntersectionObject,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity,\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<MergeIntersectionObject<Entity>>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity,\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<MergeIntersectionObject<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, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value,\n]\n ? Value extends joinable\n ? [Uppercase<Key>, Value]\n : Value extends {\n tag: infer Tag extends joinable\n value: infer Value extends joinable\n }\n ? [Tag, Value]\n : never\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity,\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 = ([PropertyKey, (key: any) => unknown] | PropertyKey)[]\nexport type TransformShape =\n | {\n tag: string\n value: joinable\n }\n | joinable\n\ntype TableEntryImpl<\n Entity,\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<E> = {\n [key in keyof E]:\n | [key, (key: E[key]) => TransformShape]\n | (undefined extends E[key] ? never : null extends E[key] ? never : key)\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity> =\n | NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>>\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<Entity, E> = {\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> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity, MergeIntersectionObject<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>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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<MergeIntersectionObject<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 const value = attributes[case_ as keyof Attributes]\n if (value == null) return undefined as never\n\n return value as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: joinable[] = []\n\n for (const keySpec of structure) {\n const [key, transform] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n\n const value = attributes[key as keyof Attributes]\n\n if (transform) {\n const transformed = transform(value as never)\n if (typeof transformed === 'object' && transformed !== null) {\n composite.push(transformed.tag)\n composite.push(transformed.value)\n } else {\n composite.push(key.toString().toUpperCase())\n composite.push(transformed)\n }\n } else if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(value as joinable)\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<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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,\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,\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,\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,\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> = [Entity] extends [never]\n ? never\n : Spec extends keyof Entity\n ? Replace<ValueOf<Attributes>, null, undefined>\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,\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 extends { [k in K]: V } ? NarrowEntity : never,\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<Entity, Schema, Separator extends string> = {\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 Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] // exclude undefined param\n ? { depth?: undefined; allowPartial?: undefined }\n : Config,\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
+ {"version":3,"sources":["../src/Rotorise.ts"],"sourcesContent":["import type {\n DistributiveOmit,\n DistributivePick,\n Exact,\n evaluate,\n MergeIntersectionObject,\n NonEmptyArray,\n Replace,\n SliceFromStart,\n ValueOf,\n} from './utils'\n\nexport type CompositeKeyParamsImpl<\n Entity,\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<MergeIntersectionObject<Entity>>[],\n skip extends number = 1,\n> = CompositeKeyParamsImpl<Entity, FullSpec, skip>\n\ntype CompositeKeyBuilderImpl<\n Entity,\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\n >\n : never\n\nexport type CompositeKeyBuilder<\n Entity extends Record<string, unknown>,\n Spec extends InputSpec<MergeIntersectionObject<Entity>>[],\n Separator extends string = '#',\n Deep extends number = number,\n isPartial extends boolean = false,\n> = CompositeKeyBuilderImpl<Entity, Spec, Separator, Deep, isPartial>\n\nexport type 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]] extends [never]\n ? `${Head[1]}`\n : `${Head[0]}${Separator}${Head[1]}`\n : [Head[0]] extends [never]\n ? `${Acc}${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 ExtractHelper<Key, Value> = Value extends joinable\n ? [Key, Value]\n : Value extends {\n tag: infer Tag extends string\n value: infer Value extends joinable\n }\n ? [Tag, Value]\n : Value extends {\n tag?: undefined\n value: infer Value extends joinable\n }\n ? [never, Value]\n : never\n\ntype ExtractPair<Entity, Spec> = Spec extends [\n infer Key extends string,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n (...key: any[]) => infer Value,\n ...(infer Default)[],\n]\n ? ExtractHelper<Uppercase<Key>, Value | Default>\n : Spec extends keyof Entity & string\n ? [Uppercase<Spec>, Entity[Spec] & joinable]\n : never\n\ntype CompositeKeyRec<\n Entity,\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\ntype InputSpecShape =\n // biome-ignore lint/suspicious/noExplicitAny: ggg\n ([PropertyKey, (key: any) => unknown, ...unknown[]] | PropertyKey)[]\nexport type TransformShape =\n | {\n tag?: string\n value: joinable\n }\n | joinable\n\ntype TableEntryImpl<\n Entity,\n Schema,\n Separator extends string = '#',\n> = Entity extends unknown\n ? {\n [Key in keyof Schema]: Schema[Key] extends DiscriminatedSchemaShape\n ? ProcessKey<\n Entity,\n ValueOf<\n Schema[Key]['spec'],\n ValueOf<Entity, Schema[Key]['discriminator']>\n >,\n Separator\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<E> = {\n [key in keyof E]:\n | (undefined extends E[key]\n ? [\n key,\n (key: Exclude<E[key], undefined>) => TransformShape,\n NonNullable<joinable>,\n ]\n : [key, (key: Exclude<E[key], undefined>) => TransformShape])\n | (undefined extends E[key] ? never : null extends E[key] ? never : key)\n}[keyof E]\n\ntype extractHeadOrPass<T> = T extends readonly unknown[] ? T[0] : T\n\ntype FullKeySpecSimple<Entity> =\n | NonEmptyArray<InputSpec<MergeIntersectionObject<Entity>>>\n | (keyof Entity & string)\n | null\n\ntype FullKeySpecSimpleShape = InputSpecShape | string | null\n\ntype DiscriminatedSchema<Entity, E> = {\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> =\n | FullKeySpecSimple<Entity>\n | DiscriminatedSchema<Entity, MergeIntersectionObject<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>() =>\n <\n const Schema extends Record<\n string,\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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<MergeIntersectionObject<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 const value = attributes[case_ as keyof Attributes]\n if (value == null) return undefined as never\n\n return value as never\n }\n\n if (config?.depth !== undefined) {\n structure = structure.slice(0, config.depth) as never\n }\n const composite: joinable[] = []\n\n for (const keySpec of structure) {\n const [key, transform, Default] = Array.isArray(keySpec)\n ? keySpec\n : [keySpec]\n\n const value = attributes[key as keyof Attributes] ?? Default\n\n if (transform && value !== undefined) {\n const transformed = transform(value as never)\n if (typeof transformed === 'object' && transformed !== null) {\n if (transformed.tag !== undefined)\n composite.push(transformed.tag)\n composite.push(transformed.value)\n } else {\n composite.push(key.toString().toUpperCase())\n composite.push(transformed)\n }\n } else if (value !== undefined && value !== null && value !== '') {\n composite.push(key.toString().toUpperCase())\n composite.push(value as joinable)\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<MergeIntersectionObject<Entity>>[]\n | keyof Entity\n | {\n discriminator: keyof Entity\n spec: {\n [val in string]:\n | InputSpec<MergeIntersectionObject<Entity>>[]\n | 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,\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,\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,\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,\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> = [Entity] extends [never]\n ? never\n : Spec extends keyof Entity\n ? Replace<ValueOf<Attributes>, null, undefined>\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 Entity,\n Spec,\n Separator extends string,\n Config extends SpecConfigShape,\n Attributes,\n> = Entity extends unknown\n ? Spec extends DiscriminatedSchemaShape\n ? ProcessKey<\n Entity,\n ValueOf<Spec['spec'], ValueOf<Entity, Spec['discriminator']>>,\n Separator,\n undefined,\n Config,\n Attributes\n >\n : ProcessKey<Entity, Spec, Separator, undefined, Config, Attributes>\n : never\n\ntype TableEntryDefinition<Entity, Schema, Separator extends string> = {\n toEntry: <const ExactEntity extends Exact<Entity, ExactEntity>>(\n item: ExactEntity,\n ) => TableEntryImpl<ExactEntity, Schema, Separator>\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 Config_ extends SpecConfigShape = [SpecConfigShape] extends [Config] // exclude undefined param\n ? { depth?: undefined; allowPartial?: undefined }\n : Config,\n >(\n key: Key,\n attributes: Attributes,\n config?: Config,\n ) => OptimizedBuildedKey<Attributes, Spec, Separator, Config_, Attributes>\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.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "Supercharge your DynamoDB with Rotorise!",
5
5
  "main": "dist/Rotorise.cjs",
6
6
  "types": "dist/Rotorise.d.ts",