Comparing version 0.1.3 to 0.2.0
@@ -0,1 +1,28 @@ | ||
<a name="0.2.0"></a> | ||
# [0.2.0](https://github.com/nicojs/node-surrial/compare/v0.1.3...v0.2.0) (2019-01-23) | ||
### Bug Fixes | ||
* remove unused typescript options ([f689593](https://github.com/nicojs/node-surrial/commit/f689593)) | ||
### Features | ||
* **Serialize:** Only serialize known class instances ([#3](https://github.com/nicojs/node-surrial/issues/3)) ([245008d](https://github.com/nicojs/node-surrial/commit/245008d)) | ||
### BREAKING CHANGES | ||
* **Serialize:** Class instances will now only be serialized in its | ||
constructor form if it is a "knownClass". | ||
```js | ||
serialize(new Foo('bar')); | ||
// Should now be: | ||
serialize(new Foo('bar'), [Foo]); | ||
``` | ||
<a name="0.1.3"></a> | ||
@@ -2,0 +29,0 @@ ## [0.1.3](https://github.com/nicojs/node-surrial/compare/v0.1.2...v0.1.3) (2018-02-23) |
{ | ||
"name": "surrial", | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"description": "Serialize anything. This is surreal!", | ||
@@ -39,20 +39,20 @@ "main": "src/index.js", | ||
"devDependencies": { | ||
"@types/chai": "^4.1.2", | ||
"@types/mocha": "^2.2.48", | ||
"@types/node": "^9.4.2", | ||
"@types/chai": "^4.1.4", | ||
"@types/mocha": "^5.2.5", | ||
"@types/node": "^10.5.5", | ||
"chai": "^4.1.2", | ||
"conventional-changelog-cli": "^1.3.13", | ||
"mocha": "^5.0.0", | ||
"nyc": "^11.4.1", | ||
"conventional-changelog-cli": "^2.0.1", | ||
"mocha": "^5.2.0", | ||
"nyc": "^12.0.2", | ||
"rimraf": "^2.6.2", | ||
"source-map-support": "^0.5.3", | ||
"stryker": "^0.19.3", | ||
"stryker-api": "^0.13.0", | ||
"stryker-html-reporter": "^0.12.1", | ||
"stryker-mocha-framework": "^0.8.3", | ||
"stryker-mocha-runner": "^0.10.5", | ||
"stryker-typescript": "^0.9.1", | ||
"tslint": "^5.9.1", | ||
"typescript": "^2.7.1" | ||
"source-map-support": "^0.5.6", | ||
"stryker": "^0.25.1", | ||
"stryker-api": "^0.18.0", | ||
"stryker-html-reporter": "^0.15.0", | ||
"stryker-mocha-framework": "^0.11.0", | ||
"stryker-mocha-runner": "^0.13.0", | ||
"stryker-typescript": "^0.12.0", | ||
"tslint": "^5.11.0", | ||
"typescript": "^3.0.1" | ||
} | ||
} |
@@ -57,10 +57,11 @@ [![Build Status](https://travis-ci.org/nicojs/node-surrial.svg?branch=master)](https://travis-ci.org/nicojs/node-surrial) | ||
Also supports serializing instances of classes. | ||
Also supports serializing instances of classes for known classes. | ||
```javascript | ||
const p = new Person('Foo', new Person('Bar', null)); | ||
const personString = serialize(p); | ||
const knownClasses = [Person]; | ||
const personString = serialize(p, knownClasses); | ||
// => 'new Person("Foo", new Person("Bar", null))' | ||
const copy = deserialize(p, [Person]); | ||
const copy = deserialize(p, knownClasses); | ||
// => Person { name: 'Foo', parent: Person { name: 'Bar', parent: null } } | ||
@@ -77,4 +78,5 @@ ``` | ||
* @param thing The thing to be serialized | ||
* @param knownClasses the classes of which instances are serialized as constructor calls (for example "new Person('Henry')"). | ||
*/ | ||
function serialize(thing: any): string { | ||
function serialize(thing: any, knownClasses: ClassConstructor[] = []): string { | ||
@@ -98,6 +100,7 @@ | ||
* Support for functions and classes using their `toString()` | ||
* Support for instances of classes (see limitations). | ||
* Support for instances of classes using `new MyClass()` syntax (see [limitations](#class-instances)). | ||
* Support for deeply nested build in types/class instances | ||
* Has a light footprint (< 200 lines of code). | ||
* Written in typescript (type definition included). | ||
* Deserialize using a `deserialize` convenience method. This uses the `new Function(/*...*/)` (comparable to `eval`) (see limitations). | ||
* Deserialize using a `deserialize` convenience method. This uses the `new Function(/*...*/)` (comparable to `eval`) (see [limitations](#deserializing-is-no-security-feature-you-will-get-hacked)). | ||
@@ -131,3 +134,3 @@ ## Limitations | ||
p.age = 10; // => ignored | ||
serialize(p); | ||
serialize(p, [Person]); | ||
// => 'new Person("foo")' | ||
@@ -153,2 +156,14 @@ ``` | ||
When serializing a class instance, only classes you specify as `knownClasses` are actually serialized using `new MyClass()`, | ||
by default it would just have a JSON format. | ||
```javascript | ||
class Person { constructor(name) { this.name = name; }} | ||
serialize(new Person('Foo')); | ||
// => { "name": "foo" } | ||
serialize(new Person('Foo'), [Person]); | ||
// => new Person("foo") | ||
``` | ||
When deserializing a class instance, you are responsible for providing a class definition (or a class with the same name). | ||
@@ -165,2 +180,3 @@ | ||
## Acknowledgements | ||
@@ -167,0 +183,0 @@ |
@@ -1,4 +0,4 @@ | ||
export default interface ClassConstructor { | ||
export default interface Constructor { | ||
name: string; | ||
new (...params: any[]): any; | ||
} |
import ClassConstructor from './ClassConstructor'; | ||
export declare function isClassInstance(thing: any): boolean; | ||
export declare function isInstanceOf(thing: any, whitelist: ReadonlyArray<ClassConstructor>): boolean; | ||
export declare function getParamList(constructor: ClassConstructor): string[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function isClassInstance(thing) { | ||
return typeof thing === 'object' && thing && thing.constructor && thing.constructor !== Object; | ||
function isInstanceOf(thing, whitelist) { | ||
return whitelist.some(function (ctor) { return thing instanceof ctor; }); | ||
} | ||
exports.isClassInstance = isClassInstance; | ||
exports.isInstanceOf = isInstanceOf; | ||
function isEcmaScriptClass(constructor) { | ||
@@ -8,0 +8,0 @@ return constructor.toString().startsWith('class'); |
@@ -12,3 +12,4 @@ import ClassConstructor from './ClassConstructor'; | ||
* @param thing The thing to be serialized | ||
* @param knownClasses the classes of which instances are serialized as constructor calls (for example "new Person('Henry')"). | ||
*/ | ||
export declare function serialize(thing: any): string; | ||
export declare function serialize(thing: any, knownClasses?: ReadonlyArray<ClassConstructor>): string; |
@@ -8,2 +8,3 @@ "use strict"; | ||
var IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g; | ||
var BUILD_IN_SUPPORTED_CLASSES = Object.freeze([Map, Array, Buffer, Set, Date, RegExp]); | ||
/** | ||
@@ -24,4 +25,6 @@ * Deserializes a string into it's javascript equivalent. CAUTION! Evaluates the string in the current javascript engine | ||
* @param thing The thing to be serialized | ||
* @param knownClasses the classes of which instances are serialized as constructor calls (for example "new Person('Henry')"). | ||
*/ | ||
function serialize(thing) { | ||
function serialize(thing, knownClasses) { | ||
if (knownClasses === void 0) { knownClasses = []; } | ||
if (thing instanceof Date) { | ||
@@ -40,22 +43,22 @@ return serializeDate(thing); | ||
else if (thing instanceof Set) { | ||
return serializeSet(thing); | ||
return serializeSet(thing, knownClasses); | ||
} | ||
else if (thing instanceof Map) { | ||
return serializeMap(thing); | ||
return serializeMap(thing, knownClasses); | ||
} | ||
else if (Array.isArray(thing)) { | ||
return serializeArray(thing); | ||
return serializeArray(thing, knownClasses); | ||
} | ||
else if (helpers_1.isClassInstance(thing)) { | ||
return serializeClassInstance(thing); | ||
else if (helpers_1.isInstanceOf(thing, knownClasses)) { | ||
return serializeClassInstance(thing, knownClasses); | ||
} | ||
else { | ||
return stringifyObject(thing); | ||
return stringifyObject(thing, knownClasses); | ||
} | ||
} | ||
exports.serialize = serialize; | ||
function serializeArray(thing) { | ||
return stringifyObject(thing); | ||
function serializeArray(thing, knownClasses) { | ||
return stringifyObject(thing, knownClasses); | ||
} | ||
function stringifyObject(thing) { | ||
function stringifyObject(thing, knownClasses) { | ||
var escapedValues = []; | ||
@@ -66,5 +69,5 @@ // Returns placeholders anything JSON doesn't support (identified by index) | ||
// If the value is an object w/ a toJSON method, toJSON is called before | ||
// the replacer runs, so we use this[key] to get the non-toJSONed value. | ||
// the replacer runs, so we use this[key] to get the non-JSON'd value. | ||
var origValue = this[key]; | ||
if ((helpers_1.isClassInstance(origValue) && !Array.isArray(origValue)) || typeof origValue === 'function') { | ||
if ((origValue !== thing && (helpers_1.isInstanceOf(origValue, BUILD_IN_SUPPORTED_CLASSES) || helpers_1.isInstanceOf(origValue, knownClasses)))) { | ||
return "@__" + UID + "-" + (escapedValues.push(origValue) - 1) + "__@"; | ||
@@ -76,3 +79,3 @@ } | ||
} | ||
var str = JSON.stringify(thing, replacer, 2); | ||
var str = JSON.stringify(thing, replacer); | ||
// Protects against `JSON.stringify()` returning `undefined`, by serializing | ||
@@ -91,13 +94,13 @@ // to the literal string: "undefined". | ||
PLACE_HOLDER_REGEXP.lastIndex = 0; | ||
return str.replace(PLACE_HOLDER_REGEXP, function (_, valueIndex) { return serialize(escapedValues[valueIndex]); }); | ||
return str.replace(PLACE_HOLDER_REGEXP, function (_, valueIndex) { return serialize(escapedValues[valueIndex], knownClasses); }); | ||
} | ||
} | ||
function serializeSet(value) { | ||
function serializeSet(value, knownClasses) { | ||
var valuesArray = []; | ||
value.forEach(function (v) { return valuesArray.push(serialize(v)); }); | ||
value.forEach(function (v) { return valuesArray.push(serialize(v, knownClasses)); }); | ||
return "new Set([" + valuesArray.join(', ') + "])"; | ||
} | ||
function serializeMap(map) { | ||
function serializeMap(map, knownClasses) { | ||
var valuesArray = []; | ||
map.forEach(function (value, key) { return valuesArray.push("[" + serialize(key) + ", " + serialize(value) + "]"); }); | ||
map.forEach(function (value, key) { return valuesArray.push("[" + serialize(key, knownClasses) + ", " + serialize(value, knownClasses) + "]"); }); | ||
return "new Map([" + valuesArray.join(', ') + "])"; | ||
@@ -111,7 +114,7 @@ } | ||
} | ||
function serializeClassInstance(instance) { | ||
function serializeClassInstance(instance, knownClasses) { | ||
var constructor = instance.constructor; | ||
if (constructor.name.length) { | ||
var params = helpers_1.getParamList(constructor); | ||
var paramValues = params.map(function (param) { return serialize(instance[param]); }); | ||
var paramValues = params.map(function (param) { return serialize(instance[param], knownClasses); }); | ||
var newExpression = "new " + constructor.name + "(" + paramValues.join(', ') + ")"; | ||
@@ -118,0 +121,0 @@ return newExpression; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
29955
185
183