.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / table / node_modules / ajv / lib / types / jtd-schema.ts
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/table/node_modules/ajv/lib/types/jtd-schema.ts b/.config/coc/extensions/node_modules/coc-prettier/node_modules/table/node_modules/ajv/lib/types/jtd-schema.ts
new file mode 100644 (file)
index 0000000..82cca9e
--- /dev/null
@@ -0,0 +1,228 @@
+/** required keys of an object, not undefined */
+type RequiredKeys<T> = {
+  [K in keyof T]-?: undefined extends T[K] ? never : K
+}[keyof T]
+
+/** optional or undifined-able keys of an object */
+type OptionalKeys<T> = {
+  [K in keyof T]-?: undefined extends T[K] ? K : never
+}[keyof T]
+
+/** type is true if T is a union type */
+type IsUnion_<T, U extends T = T> = false extends (
+  T extends unknown ? ([U] extends [T] ? false : true) : never
+)
+  ? false
+  : true
+type IsUnion<T> = IsUnion_<T>
+
+/** type is true if T is identically E */
+type TypeEquality<T, E> = [T] extends [E] ? ([E] extends [T] ? true : false) : false
+
+/** type is true if T or null is identically E or null*/
+type NullTypeEquality<T, E> = TypeEquality<T | null, E | null>
+
+/** gets only the string literals of a type or null if a type isn't a string literal */
+type EnumString<T> = [T] extends [never]
+  ? null
+  : T extends string
+  ? string extends T
+    ? null
+    : T
+  : null
+
+/** true if type is a union of string literals */
+type IsEnum<T> = null extends EnumString<Exclude<T, null>> ? false : true
+
+/** true only if all types are array types (not tuples) */
+// NOTE relies on the fact that tuples don't have an index at 0.5, but arrays
+// have an index at every number
+type IsElements<T> = false extends IsUnion<T>
+  ? [T] extends [readonly unknown[]]
+    ? undefined extends T[0.5]
+      ? false
+      : true
+    : false
+  : false
+
+/** true if the the type is a values type */
+type IsValues<T> = false extends IsUnion<Exclude<T, null>>
+  ? TypeEquality<keyof Exclude<T, null>, string>
+  : false
+
+/** true if type is a proeprties type and Union is false, or type is a discriminator type and Union is true */
+type IsRecord<T, Union extends boolean> = Union extends IsUnion<Exclude<T, null>>
+  ? null extends EnumString<keyof Exclude<T, null>>
+    ? false
+    : true
+  : false
+
+/** numeric strings */
+type NumberType = "float32" | "float64" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32"
+
+/** string strings */
+type StringType = "string" | "timestamp"
+
+/** actual schema */
+export type JTDSchemaType<T, D extends Record<string, unknown> = Record<string, never>> = (
+  | // refs - where null wasn't specified, must match exactly
+  (null extends EnumString<keyof D>
+      ? never
+      :
+          | ({[K in keyof D]: [T] extends [D[K]] ? {ref: K} : never}[keyof D] & {nullable?: false})
+          // nulled refs - if ref is nullable and nullable is specified, then it can
+          // match either null or non-null definitions
+          | (null extends T
+              ? {
+                  [K in keyof D]: [Exclude<T, null>] extends [Exclude<D[K], null>]
+                    ? {ref: K}
+                    : never
+                }[keyof D] & {nullable: true}
+              : never))
+  // empty - empty schemas also treat nullable differently in that it's now fully ignored
+  | (unknown extends T ? {nullable?: boolean} : never)
+  // all other types
+  | ((// numbers - only accepts the type number
+    true extends NullTypeEquality<T, number>
+      ? {type: NumberType}
+      : // booleans - accepts the type boolean
+      true extends NullTypeEquality<T, boolean>
+      ? {type: "boolean"}
+      : // strings - only accepts the type string
+      true extends NullTypeEquality<T, string>
+      ? {type: StringType}
+      : // strings - only accepts the type Date
+      true extends NullTypeEquality<T, Date>
+      ? {type: "timestamp"}
+      : // enums - only accepts union of string literals
+      // TODO we can't actually check that everything in the union was specified
+      true extends IsEnum<T>
+      ? {enum: EnumString<Exclude<T, null>>[]}
+      : // arrays - only accepts arrays, could be array of unions to be resolved later
+      true extends IsElements<Exclude<T, null>>
+      ? T extends readonly (infer E)[]
+        ? {
+            elements: JTDSchemaType<E, D>
+          }
+        : never
+      : // values
+      true extends IsValues<T>
+      ? T extends Record<string, infer V>
+        ? {
+            values: JTDSchemaType<V>
+          }
+        : never
+      : // properties
+      true extends IsRecord<T, false>
+      ? ([RequiredKeys<Exclude<T, null>>] extends [never]
+          ? {
+              properties?: Record<string, never>
+            }
+          : {
+              properties: {[K in RequiredKeys<T>]: JTDSchemaType<T[K], D>}
+            }) &
+          ([OptionalKeys<Exclude<T, null>>] extends [never]
+            ? {
+                optionalProperties?: Record<string, never>
+              }
+            : {
+                optionalProperties: {
+                  [K in OptionalKeys<T>]: JTDSchemaType<Exclude<T[K], undefined>, D>
+                }
+              }) & {
+            additionalProperties?: boolean
+          }
+      : // discriminator
+      true extends IsRecord<T, true>
+      ? {
+          [K in keyof Exclude<T, null>]-?: Exclude<T, null>[K] extends string
+            ? {
+                discriminator: K
+                mapping: {
+                  // TODO currently allows descriminator to be present in schema
+                  [M in Exclude<T, null>[K]]: JTDSchemaType<
+                    Omit<T extends {[C in K]: M} ? T : never, K>,
+                    D
+                  >
+                }
+              }
+            : never
+        }[keyof Exclude<T, null>]
+      : never) &
+      (null extends T
+        ? {
+            nullable: true
+          }
+        : {nullable?: false}))
+) & {
+  // extra properties
+  metadata?: Record<string, unknown>
+  // TODO these should only be allowed at the top level
+  definitions?: {[K in keyof D]: JTDSchemaType<D[K], D>}
+}
+
+type JTDDataDef<S, D extends Record<string, unknown>> =
+  | (// ref
+    S extends {ref: string}
+      ? JTDDataDef<D[S["ref"]], D>
+      : // type
+      S extends {type: NumberType}
+      ? number
+      : S extends {type: "string"}
+      ? string
+      : S extends {type: "timestamp"}
+      ? string | Date
+      : // enum
+      S extends {enum: readonly (infer E)[]}
+      ? string extends E
+        ? never
+        : [E] extends [string]
+        ? E
+        : never
+      : // elements
+      S extends {elements: infer E}
+      ? JTDDataDef<E, D>[]
+      : // properties
+      S extends {
+          properties: Record<string, unknown>
+          optionalProperties?: Record<string, unknown>
+          additionalProperties?: boolean
+        }
+      ? {-readonly [K in keyof S["properties"]]-?: JTDDataDef<S["properties"][K], D>} &
+          {
+            -readonly [K in keyof S["optionalProperties"]]+?: JTDDataDef<
+              S["optionalProperties"][K],
+              D
+            >
+          } &
+          ([S["additionalProperties"]] extends [true] ? Record<string, unknown> : unknown)
+      : S extends {
+          properties?: Record<string, unknown>
+          optionalProperties: Record<string, unknown>
+          additionalProperties?: boolean
+        }
+      ? {-readonly [K in keyof S["properties"]]-?: JTDDataDef<S["properties"][K], D>} &
+          {
+            -readonly [K in keyof S["optionalProperties"]]+?: JTDDataDef<
+              S["optionalProperties"][K],
+              D
+            >
+          } &
+          ([S["additionalProperties"]] extends [true] ? Record<string, unknown> : unknown)
+      : // values
+      S extends {values: infer V}
+      ? Record<string, JTDDataDef<V, D>>
+      : // discriminator
+      S extends {discriminator: infer M; mapping: Record<string, unknown>}
+      ? [M] extends [string]
+        ? {
+            [K in keyof S["mapping"]]: JTDDataDef<S["mapping"][K], D> & {[KM in M]: K}
+          }[keyof S["mapping"]]
+        : never
+      : // empty
+        unknown)
+  | (S extends {nullable: true} ? null : never)
+
+export type JTDDataType<S> = S extends {definitions: Record<string, unknown>}
+  ? JTDDataDef<S, S["definitions"]>
+  : JTDDataDef<S, Record<string, never>>