core/classifiers/schema.classifier.ts
core/classifiers/schema.classifier.ts is a file in GovLab Patterns. 54 lines of code and 11 definitions.
import type { Kind, Primitive } from "#types/schema.types";
import { mixedPrimitives, unsupportedValue } from "#configuration/strings/schema.strings";
import { isRecord } from "#core/predicates/record.predicate";
const SCALAR_TYPES: ReadonlySet<string> = new Set(["boolean", "number", "string"]);
export class DataLoadError extends Error {
public constructor(message: string) {
super(message);
this.name = "DataLoadError";
}
}
const listKind = function listKind(value: readonly unknown[]): Kind {
return value.length > 0 && value.every((element) => isRecord(element)) ? "list-of-objects" : "list";
};
export const kindOf = function kindOf(value: unknown): Kind {
if (Array.isArray(value)) {
return listKind(value);
}
if (isRecord(value)) {
return "object";
}
const type = typeof value;
if (SCALAR_TYPES.has(type)) {
return "scalar";
}
throw new DataLoadError(unsupportedValue(type));
};
export const primitiveOf = function primitiveOf(value: unknown, floatField: boolean): Primitive {
if (typeof value === "boolean") {
return "boolean";
}
if (typeof value === "number") {
return floatField || !Number.isInteger(value) ? "float" : "integer";
}
return "string";
};
const isFloatFamily = function isFloatFamily(primitives: ReadonlySet<Primitive>): boolean {
return (
primitives.has("float") &&
[...primitives].every((primitive) => primitive === "integer" || primitive === "float")
);
};
export const resolvePrimitive = function resolvePrimitive(name: string, primitives: ReadonlySet<Primitive>): Primitive {
if (isFloatFamily(primitives)) {
return "float";
}
const [only] = [...primitives];
if (primitives.size === 1 && only !== undefined) {
return only;
}
throw new DataLoadError(mixedPrimitives(name, [...primitives].sort((a, b) => a.localeCompare(b)).join(", ")));
};
export const isBlank = function isBlank(value: unknown): boolean {
return (value ?? null) === null;
};