All files / src compile.ts

100% Statements 24/24
100% Branches 10/10
100% Functions 6/6
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 1093x               3x         3x           3x 3x     7x                 19x   32x   1x             18x 18x       18x 2x 2x 1x     2x       2x 1x       1x         2x   16x 16x       27x                           3x                                      
import {
    diffSets,
    Evaluate,
    isRecursible,
    mergeAll,
    Narrow,
    transform
} from "@re-do/utils"
import {
    createParseFunction,
    ParseFunction,
    DefaultParseTypeOptions
} from "./parse.js"
import {
    extraneousTypesErrorMessage,
    missingTypesErrorMessage,
    TypeSet
} from "./components"
 
export const createCompileFunction =
    <DeclaredTypeNames extends string[]>(
        declaredTypeNames: Narrow<DeclaredTypeNames>
    ) =>
    <
        Definitions extends TypeSet.ValidateMemberList<
            Definitions,
            DeclaredTypeNames
        >
    >(
        // @ts-ignore
        ...definitions: Narrow<Definitions>
    ) => {
        if (
            !Array.isArray(definitions) ||
            definitions.some((def) => !isRecursible(def) || Array.isArray(def))
        ) {
            throw new Error(`Compile args must be a list of names mapped to their corresponding definitions
            passed as rest args, e.g.:
            compile(
                { user: { name: "string" } },
                { group: "user[]" }
            )`)
        }
        const typeSetFromDefinitions = mergeAll(definitions as any) as any
        const declarationErrors = diffSets(
            declaredTypeNames,
            Object.keys(typeSetFromDefinitions)
        )
        if (declaredTypeNames.length && declarationErrors) {
            const errorParts = [] as string[]
            if (declarationErrors.added) {
                errorParts.push(
                    extraneousTypesErrorMessage.replace(
                        "@types",
                        declarationErrors.added.map((_) => `'${_}'`).join(", ")
                    )
                )
            }
            if (declarationErrors.removed) {
                errorParts.push(
                    missingTypesErrorMessage.replace(
                        "@types",
                        declarationErrors.removed
                            .map((_) => `'${_}'`)
                            .join(", ")
                    )
                )
            }
            throw new Error(errorParts.join(" "))
        }
        const parse = createParseFunction(typeSetFromDefinitions) as any
        return {
            parse,
            types: transform(
                typeSetFromDefinitions,
                ([typeName, definition]) => [
                    typeName,
                    // @ts-ignore
                    parse(definition, {
                        // @ts-ignore
                        typeSet: typeSetFromDefinitions
                    })
                ]
            )
        } as CompiledTypeSet<Definitions>
    }
 
// Exported compile function is equivalent to compile from an empty declare call
// and will not validate missing or extraneous definitions
export const compile = createCompileFunction([])
 
export type CompileFunction<DeclaredTypeNames extends string[]> = <
    Definitions extends TypeSet.ValidateMemberList<
        Definitions,
        DeclaredTypeNames
    >
>(
    // @ts-ignore
    ...definitions: Narrow<Definitions>
) => CompiledTypeSet<Definitions>
 
export type CompiledTypeSet<
    Definitions,
    MergedTypeSet = TypeSet.MergeMemberList<Definitions>
> = Evaluate<{
    parse: ParseFunction<MergedTypeSet>
    types: TypeSet.Parse<MergedTypeSet, DefaultParseTypeOptions>
}>