Skip to content

Commit

Permalink
feat: map support
Browse files Browse the repository at this point in the history
  • Loading branch information
Florin Mihalache committed Jan 7, 2021
1 parent f476646 commit 1fa41ea
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 32 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
],
"rules": {
"comma-dangle": "off",
"indent": ["error", 2],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"@typescript-eslint/no-explicit-any": "off"
"@typescript-eslint/no-explicit-any": "off",
"indent": ["error", 2, {"SwitchCase": 1}]
}
}
28 changes: 28 additions & 0 deletions src/revive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,32 @@ describe('revive tests', () => {
const data = 'true'
assert.throw(() => revive(data, Number), 'expected schema type to be Boolean, got Number')
})

it('should revive a map correctly', function () {
class Prop {
value = 0
getValue() { return this.value }
}
class Person {
name = ''
props: {[key: string]: Prop} = {}
getName() { return this.name }
getProps() { return this.props }
static getRevivalSchema(): RevivalSchema<Person> {
return {
type: Person,
properties: {
props: {
map: Prop
}
}
}
}
}
const data= '{"name": "John", "props": {"foo": {"value": 1}, "bar": {"value": 2}}}'
const p = revive(data, Person)
assert.equal(p.getName(), 'John')
assert.equal(p.getProps()['foo'].getValue(), 1)
assert.equal(p.getProps()['bar'].getValue(), 2)
});
})
93 changes: 64 additions & 29 deletions src/revive.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {
defaultReviveOptions,
RevivalArraySchema,
RevivalConstructor,
RevivalConstructor, RevivalMapSchema,
RevivalObjectSchema,
RevivalOptions,
RevivalSchema, RevivalSchemaProvider,
} from './types';


function isObjectSchema<T>(schema: any): schema is RevivalObjectSchema<T> {
return 'type' in schema && 'properties' in schema
}
Expand All @@ -16,6 +15,10 @@ function isArraySchema<T>(schema: any): schema is RevivalArraySchema<T> {
return 'items' in schema
}

function isMapSchema<T>(schema: any): schema is RevivalMapSchema<T> {
return 'map' in schema
}

function isSchemaProvider(obj: any): obj is RevivalSchemaProvider<any> {
return typeof obj['getRevivalSchema'] === 'function'
}
Expand All @@ -25,6 +28,7 @@ type Revivable = string | number | {[key: string]: any} | any[]
export function revive<T>(data: Revivable, schema: RevivalObjectSchema<T>, options?: RevivalOptions): T;
export function revive<T>(data: Revivable, schema: RevivalArraySchema<T>, options?: RevivalOptions): T[];
export function revive<T>(data: Revivable, schema: RevivalConstructor<T>, options?: RevivalOptions): T;
export function revive<T>(data: Revivable, schema: RevivalMapSchema<T>, options?: RevivalOptions): {[key: string]: T};
export function revive<T>(data: Revivable, schema: RevivalSchema<T>,options: RevivalOptions = defaultReviveOptions): T {

let obj: any
Expand All @@ -46,7 +50,11 @@ function reviveAny(data: any, schema: RevivalSchema<any>, options: RevivalOption
if (isArraySchema(schema)) {
return reviveArrayAny(data, schema, options)
} else {
return reviveConstructorAny(data, schema, options)
if (isMapSchema(schema)) {
return reviveMapAny(data, schema, options)
} else {
return reviveConstructorAny(data, schema, options)
}
}
}
}
Expand All @@ -62,32 +70,32 @@ function reviveObjectAny(data: any, schema: RevivalObjectSchema<any>, options: R
}

switch(typeof data) {
case 'number':
if (schema.type !== Number) {
throw new TypeError(`expected schema type to be Number, got ${schema.type.name}`)
}
return data
case 'bigint':
if (schema.type !== Number) {
throw new TypeError(`expected schema type to be Number, got ${schema.type.name}`)
}
return data
case 'boolean':
if (schema.type !== Boolean) {
throw new TypeError(`expected schema type to be Boolean, got ${schema.type.name}`)
}
return data
case 'function':
throw new TypeError('`function` is not supported')
case 'string':
if (schema.type !== String) {
throw new TypeError(`expected schema type to be String, got ${schema.type.name}`)
}
return data
case 'symbol':
throw new TypeError('`symbol` is not supported')
case 'undefined':
return data
case 'number':
if (schema.type !== Number) {
throw new TypeError(`expected schema type to be Number, got ${schema.type.name}`)
}
return data
case 'bigint':
if (schema.type !== Number) {
throw new TypeError(`expected schema type to be Number, got ${schema.type.name}`)
}
return data
case 'boolean':
if (schema.type !== Boolean) {
throw new TypeError(`expected schema type to be Boolean, got ${schema.type.name}`)
}
return data
case 'function':
throw new TypeError('`function` is not supported')
case 'string':
if (schema.type !== String) {
throw new TypeError(`expected schema type to be String, got ${schema.type.name}`)
}
return data
case 'symbol':
throw new TypeError('`symbol` is not supported')
case 'undefined':
return data
}

if (Array.isArray(data)) {
Expand Down Expand Up @@ -141,6 +149,33 @@ function reviveArrayAny(data: any, schema: RevivalArraySchema<any>, options: Rev
return ret
}

function reviveMapAny(data: any, schema: RevivalMapSchema<any>, options: RevivalOptions): any {
const ret: {[key: string]: any} = {}

switch(typeof data) {
case 'number':
case 'bigint':
case 'boolean':
case 'function':
case 'string':
case 'symbol':
case 'undefined':
throw new TypeError(`expected an object; got an ${typeof data}`)
}

if (Array.isArray(data)) {
throw new TypeError('expected object, got array')
}

/* assign values */
for (const prop of Object.keys(data)) {
ret[prop] = reviveAny(data[prop], schema.map, options)
}

return ret
}


function reviveConstructorAny(data: any, objConstructor: RevivalConstructor<any>, options: RevivalOptions): any {
if (isSchemaProvider(objConstructor)) {
return reviveAny(data, objConstructor.getRevivalSchema(), options)
Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ export interface RevivalArraySchema<T> {
items: RevivalSchema<T>
}

export type RevivalSchema<T> = RevivalConstructor<T> | RevivalObjectSchema<T> | RevivalArraySchema<T>
export interface RevivalMapSchema<T> {
map: RevivalSchema<T>
}

export type RevivalSchema<T> = RevivalConstructor<T> | RevivalObjectSchema<T> | RevivalArraySchema<T> | RevivalMapSchema<T>

export interface RevivalSchemaProvider<T> {
getRevivalSchema(): RevivalSchema<T>
Expand Down

0 comments on commit 1fa41ea

Please sign in to comment.