diff --git a/src/index.ts b/src/index.ts index 939371e..323ec4e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,12 +13,42 @@ export interface Parser { } export interface ObjectParserRecipe { - target: Type | FunctionalParser | string; + target: Type; nestedTargets?: { [fieldName: string]: ParserRecipe | string }; } -export type ParserRecipe = ObjectParserRecipe | Type | FunctionalParser; +export type ParserRecipe = ObjectParserRecipe | FunctionalParser; export interface RepositoryRecipe { [name: string]: ParserRecipe; -} \ No newline at end of file +} + + +/** + * @todo common-lang + */ +export const isAnounymous = (obj: any) => { + return obj.name == ""; +} + +const reduceToObject = (acc, [k, v]) => Object.assign(acc, { [k as string]: v }); + +const transformValue = it => ([k, v]) => ([k, it(v)]); + +const setAtObject = obj => ([k, v]) => obj[k] = v; + +export const Mappers = { + Value: transformValue +} + +export const Reducers = { + Object: reduceToObject +} + +export const Iter = { + SetAt: setAtObject +} + +/** + * ------------ + */ \ No newline at end of file diff --git a/src/parser.ts b/src/parser.ts index 91719bd..005cdff 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,29 +1,7 @@ -import { Type, FunctionalParser, ParserRecipe, ObjectParserRecipe, Parser } from "./"; +import { Type, FunctionalParser, ParserRecipe, ObjectParserRecipe, Parser, Reducers } from "./"; import { ParserRepository } from "./repository"; import { noop, getattr } from "@huehuejs/common-lang"; - -/** - * @todo common-lang - */ -const isAnounymous = (obj: any) => { - return obj.name == ""; -} - -const reduceToObject = (acc, [k, v]) => Object.assign(acc, { [k as string]: v }); - -const transformValue = it => ([k, v]) => ([k, it(v)]); - -const Mappers = { - Value: transformValue -} - -const Reducers = { - Object: reduceToObject -} - -/** - * ------------ - */ +import { Mappers } from "." class RefParser implements Parser{ @@ -88,17 +66,14 @@ export function makeFromString(name: string): FunctionalParser { export function makeFromObjectRecipe(parserRecipe: ObjectParserRecipe): FunctionalParser { return new ObjectParser( - makeFromRecipe(parserRecipe.target), - Object.entries(parserRecipe.nestedTargets) + makeFromType(parserRecipe.target), + Object.entries(parserRecipe.nestedTargets || {}) .map(Mappers.Value(makeFromRecipe)) .reduce(Reducers.Object, {}) ).asFunctionalParser() } export function makeFromRecipe(parserRecipe: ParserRecipe | string): FunctionalParser { - if (!isAnounymous(parserRecipe) && typeof parserRecipe == "function") { - return makeFromType(parserRecipe as Type); - } if (typeof parserRecipe == "function") { return parserRecipe as FunctionalParser; } diff --git a/src/repository.ts b/src/repository.ts index 77adb3b..1713ef1 100644 --- a/src/repository.ts +++ b/src/repository.ts @@ -1,5 +1,6 @@ -import { FunctionalParser, Type } from "." +import { FunctionalParser, ParserRecipe, RepositoryRecipe, Mappers, Iter, Type } from "." import { noop, getattr } from "@huehuejs/common-lang"; +import { makeFromRecipe, makeFromType } from "./parser"; export interface ParserRepository { @@ -40,11 +41,28 @@ export class ParserRepositoryBuilder { } - add(name: string, parser: FunctionalParser): ParserRepositoryBuilder { + addParser(name: string, parser: FunctionalParser): ParserRepositoryBuilder { this.repository[name] = parser; return this; } + addType(type: Type) { + this.repository[type.name] = makeFromType(type); + return this; + } + + addRecipe(repositoryRecipe: RepositoryRecipe): ParserRepositoryBuilder { + Object.entries(repositoryRecipe) + .map(Mappers.Value(makeFromRecipe)) + .forEach(Iter.SetAt(this.repository)); + return this; + } + + addParserRecipe(name: string, recipe: ParserRecipe): ParserRepositoryBuilder { + const parser = makeFromRecipe(recipe); + return this.addParser(name, parser); + } + build(): ParserRepository { return asSelfFeederRepostiory(this.repository); } diff --git a/test/swapi.spec.ts b/test/swapi.spec.ts index c2a1a37..8ba5962 100644 --- a/test/swapi.spec.ts +++ b/test/swapi.spec.ts @@ -1,5 +1,49 @@ import { makeFromRecipe, makeFromFunction } from "../src/parser"; import { expect } from "chai"; +import { ParserRepositoryBuilder } from "../src/repository"; +import { RepositoryRecipe, Parser, FunctionalParser } from "../src"; + + + +export class Planet { + name: string//"Tatooine" + rotationPeriod: number//"23" + orbitalPeriod: number//"304" + diameter: number//"10465" + climate: string//"arid" + gravity: string//"1 standard" + terrain: string//"desert" + surfaceWater: number//"1" + population: number//"200000" + residents: Array + films: Array + created: Date//"2014-12-09T13:50:49.641000Z" + edited: Date//"2014-12-21T20:48:04.175778Z" + url: string//"https://swapi.co/api/planets/1/" +} + +const recipe: RepositoryRecipe = { + stringToNumber: makeFromFunction((it: string) => parseInt(it)), + stringToDate: makeFromFunction((it: string) => new Date(it)), + Planet: { + target: Planet, + nestedTargets: { + rotationPeriod: 'stringToNumber', + orbitalPeriod: 'stringToNumber', + diameter: 'stringToNumber', + surfaceWater: 'stringToNumber', + population: 'stringToNumber', + created: 'stringToDate', + edited: 'stringToDate', + } + } +} + +const repositoryBuilder = new ParserRepositoryBuilder(); +const repository = repositoryBuilder + .addRecipe(recipe) + .build(); + const rawPlanet = { name: 'Tatooine', @@ -36,38 +80,10 @@ const rawPlanet = { }; -export class Planet { - name: string//"Tatooine" - rotationPeriod: number//"23" - orbitalPeriod: number//"304" - diameter: number//"10465" - climate: string//"arid" - gravity: string//"1 standard" - terrain: string//"desert" - surfaceWater: number//"1" - population: number//"200000" - residents: Array - films: Array - created: Date//"2014-12-09T13:50:49.641000Z" - edited: Date//"2014-12-21T20:48:04.175778Z" - url: string//"https://swapi.co/api/planets/1/" -} - -const planetParser = makeFromRecipe({ - target: Planet, - nestedTargets: { - rotationPeriod: makeFromFunction((it: string) => parseInt(it)), - orbitalPeriod: makeFromFunction((it: string) => parseInt(it)), - diameter: makeFromFunction((it: string) => parseInt(it)), - surfaceWater: makeFromFunction((it: string) => parseInt(it)), - population: makeFromFunction((it: string) => parseInt(it)), - created: makeFromFunction((it: string) => new Date(it)), - edited: makeFromFunction((it: string) => new Date(it)), - } -}) - describe("Swapi", () => { it("Get Planet", () => { + const planetParser = repository[Planet.name] as FunctionalParser; + console.log(planetParser); const planet = planetParser(rawPlanet) expect(planet).to.instanceof(Planet) expect(typeof planet.name).to.equals("string") diff --git a/test/xparser.spec.ts b/test/xparser.spec.ts index 50d080c..9c7219e 100644 --- a/test/xparser.spec.ts +++ b/test/xparser.spec.ts @@ -102,7 +102,7 @@ describe('XParser', () => { describe("#makeFromRecipe", () => { it('should work with only a type', () => { - const justAType: ParserRecipe = Math; + const justAType: ParserRecipe = { target: Math }; const rawData = rawMathData(); const parser = makeFromRecipe(justAType); const mathData = parser(rawData); @@ -126,8 +126,8 @@ describe('XParser', () => { const rationalParser = makeFromRecipe(rationalParserRecipe); const repositoryBuilder = new ParserRepositoryBuilder(); const repository = repositoryBuilder - .add("Rational", rationalParser) - .add("number|Rational", numberOrRationalParser) + .addParser("Rational", rationalParser) + .addParser("number|Rational", numberOrRationalParser) .build(); it('should work with a complex type', () => { const rawData = {