import { ParseError } from "./errors" ; import { Queries } from "./uri" ; import { isNullOrUndefined , parseBoolean , parseInteger } from "./utility" ; import * as Fs from "fs" ; /**
 * `QueryParser` handles URI query parsing and transformation.
 * Users define the source property name and optionally the target property
 * name and a parsing function.
 */ export class QueryParser < T extends object > { private readonly functions : Map < string , MapEntry < any > > ; param descriptors returns public constructor ( descriptors ) { const withParsers = QueryParser . assertParsers ( descriptors ) ; const withTargets = QueryParser . assertTargets ( withParsers ) ; const asPairs = QueryParser . intoPairs ( withTargets ) ; this . functions = new Map < string , MapEntry < any > > ( asPairs ) ; } param query param init returns throws public parse ( query , init ) { const entries = Array . from ( this . functions . entries ( ) ) ; const hasSource = createSourceChecker < T > ( query ) ; const withSources = entries . filter ( hasSource ) ; const appendParsed = createParsedAppender < T > ( query ) ; const doParse = ( value ) => withSources . reduce ( appendParsed , value ) ; try { return doParse ( init ) ; } catch ( error ) { throw new ParseError ( `query parsing failed: ${ error }` ) ; } } param maybe returns private static assertParsers ( maybe ) { return maybe . map ( ( descriptor ) => { if ( ! isNullOrUndefined ( descriptor . parser ) ) { return descriptor as HasParser ; } const withParser = { ... descriptor , parser : ( raw ) => raw , } ; return withParser as HasParser ; } ) ; } param maybe returns private static assertTargets ( maybe ) { return maybe . map ( ( descriptor ) => { if ( ! isNullOrUndefined ( descriptor . target ) ) { return descriptor as HasTarget ; } const withTarget = { ... descriptor , target : descriptor . source , } ; return withTarget as HasTarget ; } ) ; } param descriptors returns private static intoPairs ( descriptors ) { return descriptors . map ( ( descriptor ) : [ string , MapEntry < any > ] => [ descriptor . source , { target : descriptor . target , parser : descriptor . parser } ] ) ; } } /**
 * Description of a URI query key-value pair and how to parse it into a target
 * type.
 */ export interface QueryDescriptor < T > { readonly parser ? : Parser < T > ; readonly source : string ; readonly target ? : string ; } export type Parser < T > = ( raw : string | Array < string > ) => T ; param source param target returns export const createBooleanQueryDescriptor = ( source , target ? ) : QueryDescriptor < boolean > => ( { parser : ( x ) => parseBoolean ( asScalar ( x ) ) , source , target , } ) ; param source param target returns export const createIntegerQueryDescriptor = ( source , target ? ) : QueryDescriptor < number > => ( { parser : ( x ) => parseInteger ( asScalar ( x ) ) , source , target , } ) ; param source param target returns export const createPathArrayQueryDescriptor = ( source , target ? ) : QueryDescriptor < Array < Buffer > > => ( { parser : ( x ) => asArray ( x ) . map ( ( p ) => Fs . readFileSync ( p ) ) , source , target , } ) ; param source param target returns export const createPathQueryDescriptor = ( source , target ? ) : QueryDescriptor < Buffer > => ( { parser : ( x ) => Fs . readFileSync ( asScalar ( x ) ) , source , target , } ) ; param scalarOrArray returns export const asScalar = < T > ( scalarOrArray ) : T => { if ( scalarOrArray instanceof Array ) { const array = scalarOrArray ; return array [ array . length - 1 ] ; } const scalar = scalarOrArray ; return scalar ; } ; param scalarOrArray returns export const asArray = < T > ( scalarOrArray ) : Array < T > => { if ( scalarOrArray instanceof Array ) { const array = scalarOrArray ; return array ; } const scalar = scalarOrArray ; return [ scalar ] ; } ; /**
 * An entry in `QueryParser`'s internal `Map`.
 */ interface MapEntry < T > { readonly parser : Parser < T > ; readonly target : string ; } /**
 * A `QueryDescriptor<any>` that is guaranteed to have the `parser` property.
 */ interface HasParser { readonly parser : Parser < any > ; readonly source : string ; readonly target ? : string ; } /**
 * A `QueryDescriptor<any>` that is guaranteed to have the `parser` and `target`
 * properties.
 */ interface HasTarget { readonly parser : Parser < any > ; readonly source : string ; readonly target : string ; } param query returns const createSourceChecker = < T > ( query ) => ( [ source , _ ] ) => ! isNullOrUndefined ( query [ source ] ) ; param query returns const createParsedAppender = < T extends object > ( query ) => ( previous , [ source , { target , parser } ] ) : T => { const withParsed = { ... previous as object , [ target ] : parser ( query [ source ] ! ) , } ; return withParsed as T ; } ;