diff --git a/README.md b/README.md index 733aee0..4f362f9 100644 --- a/README.md +++ b/README.md @@ -395,7 +395,7 @@ Filter properties to which this schema applies. Used with `ModelSchema.props["*" #### property `paramNumber`?: undefined | number -### _type_ `AdditionalPropArgs` = [Pick](typedoc-id-undefined)<PropSchema, > src +### _type_ `AdditionalPropArgs` = [Pick](typedoc-id-undefined)<[PropSchema](#interface-propschemasrc), `"beforeDeserialize"` | `"afterDeserialize"` | `"pattern"`> src Can be passed to function which create `PropSchema`s to set additional properties. @@ -506,7 +506,7 @@ const json = serialize(todoSchema, { title: 'Test', done: false }) const todo = deserialize(todoSchema, json) ``` -### _function_ `custom`(_serializer_: [PropSerializer](#type-propserializer--sourcepropertyvalue-any-key-string--number--symbol-sourceobject-any--any--typeof-skip-src), _deserializer_: (_jsonValue_: any, _context_: any, _oldValue_: any) => any | typeof [SKIP](typedoc-id-undefined), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `custom`(_serializer_: [PropSerializer](#type-propserializer--sourcepropertyvalue-any-key-string--number--symbol-sourceobject-any--any--typeof-skip-src), _deserializer_: (_jsonValue_: any, _context_: any, _oldValue_: any) => any | typeof [SKIP](typedoc-id-undefined), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Can be used to create simple custom propSchema. Multiple things can be done inside of a custom propSchema, like deserializing and serializing other (polymorphic) objects, skipping the serialization of something or checking the context of the obj being (de)serialized. @@ -547,27 +547,27 @@ deserialize(schemaWithAsyncProps, { "a": 6 }, (err, res) => { } ``` -### _function_ `custom`(_serializer_: [PropSerializer](#type-propserializer--sourcepropertyvalue-any-key-string--number--symbol-sourceobject-any--any--typeof-skip-src), _deserializer_: (_jsonValue_: any, _context_: any, _oldValue_: any, _callback_: (_err_: any, _result_: any | typeof [SKIP](typedoc-id-undefined)) => void) => void, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `custom`(_serializer_: [PropSerializer](#type-propserializer--sourcepropertyvalue-any-key-string--number--symbol-sourceobject-any--any--typeof-skip-src), _deserializer_: (_jsonValue_: any, _context_: any, _oldValue_: any, _callback_: (_err_: any, _result_: any | typeof [SKIP](typedoc-id-undefined)) => void) => void, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src -### _function_ `date`(_additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `date`(_additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Similar to primitive, serializes instances of Date objects -### _function_ `deserialize`<T>(_modelschema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<T>, _jsonArray_: any\[\], _callback_?: undefined | ((_err_: any, _result_: T\[\]) => void), _customArgs_?: any): T\[\] src +### _function_ `deserialize`<T>(_modelschema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<T>, _jsonArray_: any\[\], _customArgs_?: any, _callback_?: undefined | ((_err_: any, _result_: T\[\]) => void)): T\[\] src Deserializes a json structure into an object graph. This process might be asynchronous (for example if there are references with an asynchronous lookup function). The function returns an object (or array of objects), but the returned object might be incomplete until the callback has fired as well (which might happen immediately) -### _function_ `deserialize`<T>(_modelschema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<T>, _json_: any, _callback_?: undefined | ((_err_: any, _result_: T) => void), _customArgs_?: any): T src +### _function_ `deserialize`<T>(_modelschema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<T>, _json_: any, _customArgs_?: any, _callback_?: undefined | ((_err_: any, _result_: T) => void)): T src ### _function_ `getDefaultModelSchema`<T>(_thing_: any): [ModelSchema](#interface-modelschematsrc)<T> | undefined src Returns the standard model schema associated with a class / constructor function -### _function_ `identifier`(_arg1_?: [RegisterFunction](#type-registerfunction--id-any-object-any-context-context--void-src) | [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src), _arg2_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `identifier`(_arg1_?: [RegisterFunction](#type-registerfunction--id-any-object-any-context-context--void-src) | [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src), _arg2_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src -### _function_ `list`(_propSchema_: [PropSchema](#interface-propschemasrc), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `list`(_propSchema_: [PropSchema](#interface-propschemasrc), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src List indicates that this property contains a list of things. Accepts a sub model schema to serialize the contents @@ -594,15 +594,15 @@ const todo = deserialize(Todo, { }) ``` -### _function_ `map`(_propSchema_: [PropSchema](#interface-propschemasrc), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `map`(_propSchema_: [PropSchema](#interface-propschemasrc), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Similar to list, but map represents a string keyed dynamic collection. This can be both plain objects (default) or ES6 Map like structures. This will be inferred from the initial value of the targetted attribute. -### _function_ `mapAsArray`(_propSchema_: [PropSchema](#interface-propschemasrc), _keyPropertyName_: string, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `mapAsArray`(_propSchema_: [PropSchema](#interface-propschemasrc), _keyPropertyName_: string, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Similar to map, mapAsArray can be used to serialize a map-like collection where the key is contained in the 'value object'. Example: consider Map where the Customer object has the id stored on itself. mapAsArray stores all values from the map into an array which is serialized. Deserialization returns a ES6 Map or plain object object where the `keyPropertyName` of each object is used for keys. For ES6 maps this has the benefit of being allowed to have non-string keys in the map. The serialized json also may be slightly more compact. -### _function_ `object`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `object`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src `object` indicates that this property contains an object that needs to be (de)serialized using its own model schema. @@ -640,7 +640,7 @@ createModelSchema(Todo, { serialize(new Todo()) // {} ``` -### _function_ `primitive`(_additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `primitive`(_additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Indicates that this field contains a primitive value (or Date) which should be serialized literally to json. @@ -652,7 +652,7 @@ createModelSchema(Todo, { serialize(new Todo('test')) // { "title": "test" } ``` -### _function_ `raw`(_additionalArgs_: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `raw`(_additionalArgs_: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src Indicates that this field is only need to putted in the serialized json or deserialized instance, without any transformations. Stay with its original value @@ -665,7 +665,7 @@ serialize(new Model({ rawData: { a: 1, b: [], c: {} } } })) // { "rawData": { a: 1, b: [], c: {} } } } ``` -### _function_ `reference`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _lookupFn_?: [RefLookupFunction](#type-reflookupfunction--id-string-callback-err-any-result-any--void-context-context--void-src), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `reference`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _lookupFn_?: [RefLookupFunction](#type-reflookupfunction--id-string-callback-err-any-result-any--void-context-context--void-src), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src `reference` can be used to (de)serialize references that point to other models. @@ -713,9 +713,9 @@ deserialize( ) ``` -### _function_ `reference`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `reference`(_modelSchema_: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<any>, _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src -### _function_ `reference`(_identifierAttr_: string, _lookupFn_: [RefLookupFunction](#type-reflookupfunction--id-string-callback-err-any-result-any--void-context-context--void-src), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema--src)): [PropSchema](#interface-propschemasrc) src +### _function_ `reference`(_identifierAttr_: string, _lookupFn_: [RefLookupFunction](#type-reflookupfunction--id-string-callback-err-any-result-any--void-context-context--void-src), _additionalArgs_?: [AdditionalPropArgs](#type-additionalpropargs--pickpropschema-beforedeserialize--afterdeserialize--pattern-src)): [PropSchema](#interface-propschemasrc) src ### _function_ `serializable`(_propSchema_: [PropDef](#type-propdef--propschema--boolean--undefined-src)): (_target_: any, _key_: string, _baseDescriptor_?: [PropertyDescriptor](typedoc-id-undefined)) => void src @@ -793,7 +793,9 @@ Sets the default model schema for class / constructor function. Everywhere where When passing an instance of this class to `serialize`, it is not required to pass the model schema as first argument anymore, because the default schema will be inferred from the instance type. -### _function_ `update`(_modelSchema_: any, _target_: any, _json_: any, _callback_: any, _customArgs_?: any): void src +### _function_ `update`<T>(_target_: T, _json_: any, _modelSchema_?: [ClazzOrModelSchema](#type-clazzormodelschemat--modelschemat--clazzt-src)<T>, _customArgs_?: any, _callback_?: any): void src + +Similar to deserialize, but updates an existing object instance. Properties will always updated entirely, but properties not present in the json will be kept as is. Further this method behaves similar to deserialize. # Recipes and examples diff --git a/gendoc.tsx b/gendoc.tsx index faf7e9e..04772cc 100644 --- a/gendoc.tsx +++ b/gendoc.tsx @@ -209,6 +209,20 @@ function TypeParameters({ of: typeParameters }: { of: JSONOutput.TypeParameterRe ) } +function TypeArguments({ of: typeParameters }: { of: JSONOutput.TypeParameterReflection[] }) { + // tslint:disable-next-line:no-null-keyword react requires null return value + if (!typeParameters) return null + return ( + <> + {"<"} + {reactJoin( + typeParameters.map(t => ), + ", " + )} + {">"} + + ) +} function Signature({ of, prefix, @@ -241,7 +255,7 @@ function Type(type: any) { return ( <> {type.name} - + ) case "intrinsic": diff --git a/src/core/deserialize.ts b/src/core/deserialize.ts index 0b13627..5ea9c11 100644 --- a/src/core/deserialize.ts +++ b/src/core/deserialize.ts @@ -76,20 +76,20 @@ function deserializeStarProps( export default function deserialize( modelschema: ClazzOrModelSchema, jsonArray: any[], - callback?: (err: any, result: T[]) => void, - customArgs?: any + customArgs?: any, + callback?: (err: any, result: T[]) => void ): T[] export default function deserialize( modelschema: ClazzOrModelSchema, json: any, - callback?: (err: any, result: T) => void, - customArgs?: any + customArgs?: any, + callback?: (err: any, result: T) => void ): T export default function deserialize( clazzOrModelSchema: ClazzOrModelSchema, json: any | any[], - callback: (err?: any, result?: T | T[]) => void = GUARDED_NOOP, - customArgs?: any + customArgs?: any, + callback: (err?: any, result?: T | T[]) => void = GUARDED_NOOP ): T | T[] { invariant(arguments.length >= 2, "deserialize expects at least 2 arguments") const schema = getDefaultModelSchema(clazzOrModelSchema) diff --git a/src/core/update.ts b/src/core/update.ts index 3e8f097..f1e5c43 100644 --- a/src/core/update.ts +++ b/src/core/update.ts @@ -13,44 +13,21 @@ import { ClazzOrModelSchema } from "../api/types" * Properties will always updated entirely, but properties not present in the json will be kept as is. * Further this method behaves similar to deserialize. * - * @param modelSchema, optional if it can be inferred from the instance type * @param target target instance to update * @param json the json to deserialize - * @param callback the callback to invoke once deserialization has completed. + * @param modelSchema, optional if it can be inferred from the target type * @param customArgs custom arguments that are available as `context.args` during the deserialization process. This can be used as dependency injection mechanism to pass in, for example, stores. + * @param callback the callback to invoke once deserialization has completed. * @returns deserialized object, possibly incomplete. */ -export function update( - modelschema: ClazzOrModelSchema, - instance: T, - json: any, - callback?: (err: any, result: T) => void, - customArgs?: any -): void -export function update( - instance: T, +export default function update( + target: T, json: any, - callback?: (err: any, result: T) => void, - customArgs?: any -): void -export default function update( - modelSchema: any, - target: any, - json: any, - callback: any, - customArgs?: any + modelSchema?: ClazzOrModelSchema, + customArgs?: any, + callback?: any ) { - const inferModelSchema = arguments.length === 2 || typeof arguments[2] === "function" // only target and json // callback as third arg - - if (inferModelSchema) { - target = arguments[0] - modelSchema = getDefaultModelSchema(target) - json = arguments[1] - callback = arguments[2] - customArgs = arguments[3] - } else { - modelSchema = getDefaultModelSchema(modelSchema) - } + modelSchema = getDefaultModelSchema(modelSchema || target) invariant(isModelSchema(modelSchema), "update failed to determine schema") invariant( typeof target === "object" && target && !Array.isArray(target), diff --git a/test/classes.js b/test/classes.js index a8c0cbb..d8995d8 100644 --- a/test/classes.js +++ b/test/classes.js @@ -25,7 +25,7 @@ test("schema's can be defined on constructors", t => { }) t.equal(res.title, "bloop") - _.update(Todo, res, { + _.update(res, { title: "bloop2" }) t.equal(res.title, "bloop2") @@ -136,7 +136,7 @@ test("complex async schema", t => { comments: [2, 3] }) - var clone = _.deserialize(Post, serialized, function(err, r) { + var clone = _.deserialize(Post, serialized, undefined, function(err, r) { t2.notOk(err) t2.ok(clone === r) t2.equal(r.comments.length, 2) @@ -237,16 +237,11 @@ test("test context and factories", t => { } } - var res = _.deserialize( - messageModel, - json, - (err, message) => { - t.ok(message === theMessage) - t.notOk(err) - t.deepEqual(_.serialize(messageModel, message), json) - }, - myArgs - ) + var res = _.deserialize(messageModel, json, myArgs, (err, message) => { + t.ok(message === theMessage) + t.notOk(err) + t.deepEqual(_.serialize(messageModel, message), json) + }) t.ok(res === theMessage) t.end() @@ -312,7 +307,7 @@ test("async error handling with handler", t => { ) }) - var a = _.deserialize(parent, { r: [1, 42] }, (err, res) => { + var a = _.deserialize(parent, { r: [1, 42] }, undefined, (err, res) => { t.notOk(res) t.ok(a) t.equal(err, "oops") @@ -389,6 +384,7 @@ test("default reference resolving", t => { { from: 3, to: 2 } ] }, + undefined, (err, res) => { t2.notOk(res) t2.equal("" + err, 'Error: Unresolvable references in json: "3", "4"') diff --git a/test/simple.js b/test/simple.js index 09d3bc0..25163f5 100644 --- a/test/simple.js +++ b/test/simple.js @@ -22,14 +22,14 @@ test("it should serialize simple object", t1 => { t.deepEqual(deserialize(schema, s), { x: 42 }) var d = { x: 1 } - update(schema, a, d) + update(a, d, schema) t.deepEqual(a, { y: 1337, x: 1 }) test("it should skip missing attrs", t3 => { - update(schema, a, {}, (err, res) => { + update(a, {}, schema, undefined, (err, res) => { t3.ok(res === a) t3.notOk(err) t3.equal(res.x, 1) @@ -49,14 +49,14 @@ test("it should serialize simple object", t1 => { t.deepEqual(deserialize(schema, s), {}) var d = { x: 1 } - update(schema, a, d) + update(a, d, schema) t.deepEqual(a, { y: 1337, x: 1 }) test("it should skip missing attrs", t3 => { - update(schema, a, {}, (err, res) => { + update(a, {}, schema, undefined, (err, res) => { t3.ok(res === a) t3.notOk(err) t3.equal(res.x, 1) @@ -88,7 +88,7 @@ test("it should support 'false' and 'true' propSchemas", t => { var a = { x: 1, y: 2 } t.deepEqual(_.serialize(s, a), { x: 1 }) - _.update(s, a, { x: 4, y: 3 }) + _.update(a, { x: 4, y: 3 }, s) t.equal(a.x, 4) t.equal(a.y, 2) t.end() @@ -237,14 +237,14 @@ test("it should not serialize values for optional properties", t => { t.deepEqual(deserialize(schema, s), {}) var d = { optionalProp: 1 } - update(schema, a, d) + update(a, d, schema) t.deepEqual(a, { y: 1337, optionalProp: 1 }) test("it should skip missing attrs", t3 => { - update(schema, a, {}, (err, res) => { + update(a, {}, schema, undefined, (err, res) => { t3.ok(res === a) t3.notOk(err) t3.equal(res.optionalProp, 1) @@ -418,7 +418,7 @@ test("it should support maps", t => { t.deepEqual(deserialize(schema, json), source) // recycle objects if possible - update(schema, source, { x: { bar: 3, baz: 4 } }) + update(source, { x: { bar: 3, baz: 4 } }, schema) t.deepEqual(source, { x: { bar: 3, baz: 4 } }) t.end() @@ -452,7 +452,7 @@ test("it should support ES6 maps", t => { // recycle objects if possible var m = source.x - update(schema, source, { x: { bar: 3, baz: 4 } }) + update(source, { x: { bar: 3, baz: 4 } }, schema) t.deepEqual(serialize(schema, source), { x: { bar: 3, baz: 4 } }) t.ok(source.x === m) t.ok(source.x instanceof Map) @@ -492,7 +492,7 @@ test("it should support mapAsArray", t => { //recycle objects if possible var m = source.x - update(schema, source, { x: [{ id: 3, name: "Luke" }] }) + update(source, { x: [{ id: 3, name: "Luke" }] }, schema) t.deepEqual(serialize(schema, source), { x: [{ id: 3, name: "Luke" }] }) t.ok(source.x === m) t.ok(source.x instanceof Map) diff --git a/test/typescript/ts.ts b/test/typescript/ts.ts index c204ea4..8c9822b 100644 --- a/test/typescript/ts.ts +++ b/test/typescript/ts.ts @@ -212,7 +212,7 @@ test("[ts] custom prop schemas", t => { } t.deepEqual(result, initial) - deserialize(A, updated, (err, resultObj) => { + deserialize(A, updated, undefined, (err, resultObj) => { err ? t.end(err) : null result = serialize(resultObj) t.deepEqual(result, updated) @@ -571,7 +571,7 @@ test("[ts] additional lifecycle handlers 'beforeDeserialize' and 'afterDeseriali } let resultIsFinal = false - const prelimResult = deserialize(FinalData, jsonInput, (err, result) => { + const prelimResult = deserialize(FinalData, jsonInput, undefined, (err, result) => { resultIsFinal = true err ? t.end(err) : null t.deepEqual(serialize(result), jsonResult)