diff --git a/.gitignore b/.gitignore index a02162c..4cfbc9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ node_modules .idea - +dist spec/spec spec/src .gulp*** gulp-** +coverage \ No newline at end of file diff --git a/README.md b/README.md index 9071835..b24c674 100644 --- a/README.md +++ b/README.md @@ -1,226 +1,441 @@ # Cerialize + Easy serialization through ES7/Typescript annotations This is a library to make serializing and deserializing complex JS objects a breeze. It works by applying meta data annotations (as described in ES7 proposal and experimental Typescript feature) to fields in a user defined class. + +## Concepts +This library works by processing annotations on class types. Annotations are provided for reading (deserializing) and writing (serializing) values to and from json. + +Once you have annotated your class types, you can use the `Serialize*` and `Deserialize*`functions to serialize and deserialize your data. + ## Example + ```typescript -var pet = new Pet('Cracker', 'Cat'); -var person = new Person('Matt', new Date(1989, 4, 3), 'coding', pet); -var json = Serialize(person); -/* json = { - name: 'Matt', - birthdate: 'Wed May 03 1989 00:00:00 GMT-0400 (EDT)', - favorite_hobby: 'coding', - 'favorite_pet': { - Name: 'Cracker', - animalType: 'Cat', - hobby: 'laser pointers' - } - } -*/ + + const ship = new Starship(); + /* assume values assigned */ + const json = Serialize(ship, Starship); + /* + json = { + remainingFuel: 500.5, + capt: { + name: "Sparrow", + onDuty: true, + credits: { amount: 500, currency: "galactic" } + }, + crew: [ + { + name: "Bill", + onDuty: true, + credits: { amount: 0, currency: "galactic" } + }, + { + name: "Ben", + onDuty: false, + credits: { amount: 1500, currency: "galactic" } + }, + { + name: "Bob", + onDuty: true, + credits: { amount: 50, currency: "galactic" } + } + ], + planetsVisited: { + Tatooine: { + timeVisited: "Mon Feb 05 2018 11:35:42 GMT+0100 (CET)", + description: "desert" + }, + Yavin4: { + timeVisited: "Tue Feb 06 2018 11:35:42 GMT+0100 (CET)", + description: "jungle" + }, + Endor: { + timeVisited: "Wed Feb 07 2018 11:35:42 GMT+0100 (CET)", + description: "forest" + } + }, + cargo: { + containers: 4, + contents: ["lots", "of", "stuff"] + } + } + */ + const instance = Deserialize(json, Starship); ``` + ## Details ```typescript -import { serialize, serializeAs } from 'cerialize'; -class Pet { - //keys can be customized using serializeAs(string) - @serializeAs('Name') public name : string; - @serialize animalType : string; - - constructor(name : string, animalType : string) { - this.name = name; - this.animalType = animalType; - } - - //this callback runs after the object is serialized. JSON can be altered here - public static OnSerialized(instance : Pet, json : any) : void { - json['addiction'] = 'laser pointers'; - } -} - -class Person { - //primitive properties marked with @serialize will be serialized as is - @serialize public name : string; - - //complex types like Date or a user defined type like `User` use the serializeAs(keyNameOrType, keyName?) construct - @serializeAs(Date) public birthdate : Date; - - //serialize key name as `favorite_hobby` instead of `hobby` - @serializeAs('favorite_hobby') public hobby : string; - - //serialize the key name as `favorite_pet` and treat it like a `Pet` - @serializeAs(Pet, 'favorite_pet') public pet : Pet; - - - public firstName : string; //things not marked with an annotation are not serialized - - constructor(name : string, birthdate : Date, hobby : string, pet : Pet) { - this.name = name; - this.firstName = name.split(' ')[0]; - this.birthdate = birthdate; - this.hobby = hobby; - this.pet = pet; - } - -} - + class CrewMemeber { + + //unannotated properties are not serialized or deserialized, they are totally ignored + localId :number; + + //serialize and deserialize the crew name as a string + @autoserializeAs(String) name : string; + + //serialize the onDuty property as a boolean, don't deserialize it + @serializeAs(Boolean) onDuty : boolean; + + //deserialize the happiness rating as a number, don't serialize it + @deserializeAs(Number) happinessRating : number; + + //we only want to write our credit value, never deserialize it + //we want to transform the value into a representation our server + //understands which is not a direct mapping of number values. + //use a custom serialization function instead of a type. + @serializeUsing(CreditSerializer) credits : number; + } + + class PlanetLog { + + // we handle the timeVisited field specially in our callbacks + // we do not annotate it so that we can customize it outselves + timeVisited : Date; + + // serialize and deserialize description as a string + @autoserializeAs(String) description : string; + + // when serializing our planet log we need to convert the timezone + // of the timeVisited value from local time to galactic time + // (This could also be done via @serializeUsing(Time.toGalacticTime)) + static onSerialized(instance : PlanetLog, json : JsonObject) { + json["timeVisited"] = Time.toGalacticTime(instance.timeVisited); + } + + // when deserializing our planet log we need to convert the timezone + // of the timeVisited value from galactic to local time + // (This could also be done via @deserializeUsing(Time.toLocalTime)) + static onDeserialized(instance : PlanetLog, json : JsonObject, instantiationMethod : boolean) { + instance.timeVisited = Time.toLocalTime(instance.timeVisited); + } + + } + + class Starship { + + // when writing our fuel value to the server, we have a number but the server expects a string + // when reading our fuel value from the server, we receive a string but we want a number + @serializeAs(String) + @deserializeAs(Number) + remainingFuel : number; + + // keys can be customized by providing a second argument to any of the annotations + @autoserializeAs(CrewMember, "capt") captain : CrewMember; + + // serialize and deserialize the crew members as an array + @autoserializeAsArray(CrewMember) : crew : Array; + + // serialize and deserialize our planet log as an indexable map by planet name + @autoserializeAsMap(Planet) : planetsVisited : Indexable; + + // we don't have a specific format for cargo, so just serialize and deserialize it as normal json + @autoserializeAsJSON() cargo : any; + + } + + // a function to transform our credit amount into a format our server understands + function CreditSerializer(instance : { credits : number }) : JsonType { + return { amount: instance.credits, currency: "galactic" }; + } ``` - -After defining which properties should be serialized, deserialized, or both, the actual marshalling is handled by a trio of simple functions. - -* `Serialize(value, classType?)` takes in a value and spits out a serialized value using the algorithm described in [Serializing Objects](#serializing_objects) - -* `Deserialize(rawObject, classType)` takes an untyped js object or array and a class type to deserialize it into and returns a new instance of `classType` with all the deserialized properties from `rawObject` using the algorithm described in [Deserializing Objects](#deserializing_new_instances) - -* `DeserializeInto(rawObject, instance)` takes an untyped js object or array and an instance to populate with the new data, reusing any fields that are reference types and already exist on `instance` where possible and creating the fields where not. This is described in detail in [Deserializing Into Existing Objects](#deserializing_existing_instances) - -## Serializing Objects - -Calling `Serialize(value, classType?)` on something will serialize it into a pre-stringified json object. You must call `JSON.stringify` to make it a string. Serialization works through the following alorithm: - -1. If `value` is an array, all items in the array will be have `Serialize` called on them (with `classType` argument if given). - -2. If `classType` is given, the `value` is considered like an instance of this object class (see `3` and `4`). - -3. If `value` is an object that has any properties marked with a serializtion annotation, or inherits any properties marked for serialization, only those properties marked for serialization will be serialized. Anything without an annotation will not have `Serialize` called on them. - -4. If `value` is an object that does not have any properties marked for serialization and does not inherit any properties marked for serialization, all keys in that object will be serialized as primtives, unless the value at a given key is an instance of a class with serialized properties, in which case it will be serialized as described above in 2. - -5. If `value` is a primitive, it will be returned as is. - -6. If `value` is `undefined`, `Serialize` will return `null`. - +## Annotations + +When annotating your classes you can declare which fields get treated as which kinds of values and how they are read and written to and from json format. To specify how fields are written to json, use `@serialize*` annotations. For writing, use `@deserialize*`. + +Most annotations take a class constructor. For primitives, use `String`, `Number`, `Boolean`, `Date`, or `RegExp`. For other types, provide the corresponding type constructor. All annotations take an optional argument `customKey` which will overwrite the corresponding key in the output. If no `customKey` is provided, the property key will be the same as defined in the class. For example, if our class has a field called `protons` but our server sends json with `particles` instead, we would use "particles" as the `customKey` value. If no `customKey` is provided, the property key will be the same as defined in the class. + +If you want the same behavior for a property when serializing and deserializing, you can either tag that property with a `@serialize*` and `@deserialize*` or you can use `@autoserializeXXX` which will do this in a single annotation and behave exactly the same as `@serialize*` and `@deserialize*`. The only difference in behavior is that `@autoserializingUsing()` takes an argument of type `SerializeAndDeserializeFns` instead of a single function argument like it's siblings do. + +##### Serialization +- `@serializeAs(type : ClassConstructor, customKey? : string)` +- `@serializeAsMap(type : ClassConstructor, customKey? : string)` +- `@serializeAsArray(type : ClassConstructor, customKey? : string)` +- `@serializeUsing(transform : SerializerFn, customKey? : string)` +- `@serializeAsJson(customKey? : string)` +##### Deserialization +- `@deserializeAs(type : ClassConstructor, customKey? : string)` +- `@deserializeAsArray(type : ClassConstructor, customKey? : string)` +- `@deserializeAsMap(type : ClassConstructor, customKey? : string)` +- `@deserializeUsing(transform : DeserializerFn, customKey? : string)` +- `@deserializeAsJson(customKey? : string)` +##### Serialization and Deserialization +- `@autoserializeAs(type : ClassConstructor, customKey? : string)` +- `@autoserializeAsMap(type : ClassConstructor, customKey? : string)` +- `@autoserializeAsArray(type : ClassConstructor, customKey? : string)` +- `@autoserializeUsing(transforms : SerializeAndDeserializeFns, customKey? : string)` +- `@autoserializeAsJson(customKey? : string)` +##### Types ```typescript -import { serialize, Serialize } from 'cerialize'; - -class Product { - - // Will be serialized as is - @serialize public name : string; - - // Will not be serialized - public sku : string; - - constructor(name : string, sku : string) { - this.name = name; - this.sku = sku; - } -} - -var product = new Product('47Z Phone', '47Z-S'); -var serializedProduct = Serialize(product); -console.log(JSON.stringify(serializedProduct)); // Will display : {name: '47Z Phone'} - -var productJson = {name: '47Z Phone', sku: '47Z-S'}; -var serializedProductJson = Serialize(productJson); -console.log(JSON.stringify(serializedProductJson)); // Will display : {name: '47Z Phone', sku: '47Z-S'} - -var serializedProductJsonToObject = Serialize(productJson, Product); -console.log(JSON.stringify(serializedProductJsonToObject)); // Will display : {name: '47Z Phone'} + type SerializationFn = (target : T) => JsonType; + type DeserializationFn = (data : JsonType, target? : T, instantiationMethod? : InstantiationMethod) => T + type SerializeAndDeserializeFns = { + Serialize: SerializationFn, + Deserialize: DeserializationFn + } ``` -## Deserializing Into New Instances -The simplest way to deserialize a piece of JSON is to call `Deserialize(json, type)` on it. This function takes the provided type and pulls out all the properties you tagged with `@deserialize`, `@deserializeAs(keyNameOrType, keyName?)`, `@autoserialize` or `@autoserializeAs(keyNameOrType, keyName?)` and will pump them (recursively) into a new instance of `type` which is returned. If your type marks a property for deserialization that is itself tagged with deserialization annotations, that property will be hydrated into it's type following the same deserialization algorithm. +## Serializing Data to JSON +Calling any of the `Serialize*` family of methods will convert the input object into json. The output is a plain javascript object that has not had `JSON.stringify` called on it. + +#### Functions for Serializing +Depending on how your data is structured there are a few options for serialization. You can work with single objects, maps of objects, or arrays of objects. + +- `Serialize(target : T, ClassConstructor) => JsonObject` + ```typescript + /* takes a single object and serializes it using the provided class type. */ + const ship = new Starship(); + const json = Serialize(ship, Starship); + ``` +- `SerializeArray(target : Array, ClassConstructor) => JsonArray` + ```typescript + /* takes an array of objects and serializes each entry using the provided class type */ + const ships : Array; + const json = SerializeArray(ships, Starship); + ``` +- `SerializeMap(target: Indexable, ClassConstructor) => JsonObject` + ```typescript + /* takes an indexable object ie `{ [idx: string] : T }` and for each key serializes + the object using the provided class type. */ + const ships : Indexable = { + ship1: new Starship(), + ship2: new Starship() + }; + const json = SerializeMap(ships, Starship); + ``` +- `SerializeJson(target : any) => JsonType` + ```typescript + /* takes any value and serializes it as json, no structure is assumed + and any serialization annotations on any processed objects are totally ignored. */ + + const value = {}; /* anything that isn't a function */ + const json = SerializeJson(value); + ``` + +## Deserializing From JSON + +Calling any of the `Deserialize*` family of methods will convert the input json into an instance of the provided ClassConstructor or a plain JS object if that is preferred (Redux for example, expects plain objects and not instances) + +The simplest way to deserialize a piece of JSON is to call `Deserialize(json, type)` on it. This function takes the provided type and pulls out all the properties you've tagged with `@deserializeXXX` or `@autoserializeXXX`. It will pump them (recursively) into a new instance of type which is returned. If your type marks a property for deserialization that is itself tagged with deserialization annotations, that property will be hydrated into it's type following the same deserialization algorithm. + +#### Deserializing Into Existing Instances + +It is also possible to re-use existing objects when deserializing with `Deserialize(json, Type, target)`. You might want to do this so that you can maintain references to things even after updating their properties. This is handled exactly the same way as `Deserialize(json, Type)` except that it takes one additional argument, the object you want to deserialize properties into. If the target instance you provide is null or undefined, this behaves identically to `Deserialize(json, Type)`, otherwise the deserialization will always use existing objects as write targets (if they are defined and of the expected type) instead of creating new ones. ```typescript -class Tree { - @deserialize public species : string; - @deserializeAs(Leaf) public leafs : Array; //arrays do not need extra specifications, just a type. - @deserializeAs(Bark, 'barkType') public bark : Bark; //using custom type and custom key name - @deserializeIndexable(Leaf) public leafMap : {[idx : string] : Leaf}; //use an object as a map -} - -class Leaf { - @deserialize public color : string; - @deserialize public blooming : boolean; - @deserializeAs(Date) public bloomedAt : Date; -} - -class Bark { - @deserialize roughness : number; -} -var json = { - species: 'Oak', - barkType: { roughness: 1 }, - leafs: [ {color: 'red', blooming: false, bloomedAt: 'Mon Dec 07 2015 11:48:20 GMT-0500 (EST)' } ], - leafMap: { type1: { some leaf data }, type2: { some leaf data } } -} -var tree = Deserialize(json, Tree); + const existingInstance = new Type(); + const instance = Deserialize(json, Type, existingInstance); + expect(existingInstance === instance).toBe(true); ``` -## Deserializing Into Existing Instances -It is also possible to re-use existing objects when deserializing with `DeserializeInto(json, Type, target)`. You might want to do this so that you can maintain references to things even after updating their properties. This is handled exactly the same way as `Deserialize(json, Type)` except that it takes one additional argument, the object you want to deserialize properties into. If the target instance you provide is null or undefined, this behaves identically to `Deserialize`. +#### Deserializing Into Plain Objects + +The `instantiationMethod` parameter can be used to change the way in which instances of the input type are created. With `InstantiationMethod.New`, the constructor will be invoked when a new instance needs to be created. With `InstantiationMethod.ObjectCreate`, the object will be created without invoking its constructor, which is useful for systems where constructed objects immediately freeze themselves. With `InstantiationMethod.None`, the `deserializeXXX` functions will return a plain object instead, which can be useful for systems like Redux that expect / require plain objects and not class instances. ```typescript - //reusing the above class and json structures - var localTree = new Tree(); - var leaf = new Leaf(); - leaf.color = 'blue'; - localTree.leafMap = { type1: new Leaf(), type2: new Leaf() } - localTree.leafs[0] = leaf; - DeserializeInto(json, Tree, localTree) - expect(localTree.leafs[0]).toEqual(leaf) //true, the leaf instance was reused but has a differnt color - expect(localTree.leafs[0].color).toEqual('red'); //red comes from the json defined earlier - expect(localTree.leafMap['type1']).color).toEqual('red') //this is how `@xxxIndexable` works + import {Deserialize, Instances} from 'cerialize'; + + class Immutable { + + public value : string; + + constructor(value : string) { + this.value = value; + Object.freeze(this); + } + + public getValue() : string { + return value; + } + + } + + Deserialize({value: 'example'}, Immutable, InstantiationMethod.New); // Error because of Object.freeze + Deserialize({value: 'example'}, Immutable, InstantiationMethod.ObjectCreate); // Immutable {value 'example'} + Deserialize({value: 'example'}, Immutable, InstantiationMethod.None); // Object {value: 'example'} ``` -## Serializing and Deserializing -If you want the same behavior for a property when serializing and deserializing, you can either tag that property with a `@serialize` and `@deserialize` (or their `As` variants) or you can use `@autoserialize` and `@autoserializeAs(keyNameOrType, keyName?)` which will do this in a single annotation and behave exactly the same as `@serialize` and `@deserialize`. `@autoserializeIndexable`(and friends) will retain type information while allowing an object to be used as a dictionary, without this the system would treat your input object as whatever type you provide instead of a map of objects of that type. +The default InstantiationMethod can be changed with `SetDefaultInstantiationMethod(instantiationMethod : InstantiationMethod)` + +##### Functions +- `Deserialize(json : JsonObject, ClassConstructor, target? : T) : T` + ```typescript + /* takes a single object and serializes it using the provided class type. */ + + const json = {/* some values from server */}; + const existingInstance = new Starship(); + const instance = Deserialize(json, Starship); // make a new instance + + Deserialize(json, Starship, existing); // re-use our existing instance + ``` +- `DeserializeArray(json : JsonArray, ClassConstructor, target? : Array) : Array` + ```typescript + const json = [ + {/* some values from server */}, + {/* some values from server */}, + {/* some values from server */} + ]; + const existingInstances = [ new Starship(), new Starship() ]; + const existingArray = [ new Starship() ]; + + const array = DeserializeArray(json, Starship); // make a new array of instances + + /* re-use our existing array, if possible use existing instances in array, otherwise create new ones */ + DeserializeArray(json, Starship, existingArray); + ``` +- `DeserializeMap(json : JsonObject, ClassConstructor, target? : Indexable) : Indexable` + ```typescript + const json = { + ship0: {/* some values from server */}, + ship1: {/* some values from server */}, + ship2: {/* some values from server */} + }; + const existingMap = { + ship0: new Starship(), + ship3: new Starship() + ]; + + const map = DeserializeMap(json, Starship); // make a new map of instances + + /* re-use our existing map, in the case of key collision, + write new property values into existing instance + otherwise create new ones */ + DeserializeMap(json, Starship, existingMap); + ``` +- `DeserializeJson(json : JsonType, target? : any) : any` + ```typescript + /* takes any value and deserializes it from json, no structure is assumed + and any deserialization annotations on any processed objects are totally ignored. */ + + const value = { /* anything that isn't a function */ }; + const json = DeserializeJson(value); + ``` + +- `DeserializeRaw(data : JsonObject, type : SerializableType, target? : T) : T` + ```typescript + const json = {/* some values from server */}; + + //deserialize into a new object + const newObject = DeserializeRaw(json, Starship); + + //deserialize into an existing object + const existingObject = {}; + DeserializeRaw(json, Starship, existingObject); + ``` +- `DeserializeArrayRaw(data : JsonArray, type : SerializableType, target? : Array) : Array` + ```typescript + const json = [ + {/* some values from server */}, + {/* some values from server */}, + {/* some values from server */} + ]; + + // make a new array of plain objects + const plainObjectArray = DeserializeArrayRaw(json, Starship); + const existingArray = [{}, {}]; + + const value0 = existingArray[0]; + const value1 = existingArray[1]; + + /* re-use our existing array, if possible use existing plain objects in array, otherwise create new ones */ + DeserializeArrayRaw(json, Starship, existingArray); + expect(existingArray[0]).toBe(value0); + expect(existingArray[1]).toBe(value1); + expect(existingArray.length).toBe(3); + + ``` +- `DeserializeMapRaw(data : Indexable, type : SerializableType, target? : Indexable) : Indexable` + ```typescript + const json = { + ship0: {/* some values from server */}, + ship1: {/* some values from server */}, + ship2: {/* some values from server */} + }; + const plainObjectMap = DeserializeMapRaw(json, Starship); // make a new map of plain objects + const existingMap = { + ship0: {}, + ship3: {} + } + /* re-use our existing map, if possible use existing plain objects in map, otherwise create new ones */ + DeserializeMapRaw(json, Starship, existingMap); + ``` + + +## onSerialized Callback +A callback can be provided for when a class is serialized. To define the callback, add a static method `onSerialized(instance : T, json : JsonObject)` to the class that needs custom post processing. You can either return a new value from this function, or modify the `json` parameter. + +```typescript + class CrewMember { + + @autoserializeAs(String) firstName; + @autoserializeAs(String) lastName; + + static onSerialized(instance : CrewMember, json : JsonObject) { + json["employeeId"] = instance.lastName.toUpperCase() + ", " + instance.firstName.toUpperCase(); + } + + } +``` -## Callbacks +## onDeserialized Callback +A callback can be provided for when a class is deserialized. To define the callback, add a static method `onDeserialized(data : JsonObject, instance : T, instantiationMethod = InstantationMethod.New)` to the class that needs custom post processing. You can either return a new value from this function, or modify the `instance` parameter. The `instantiationMethod` parameter signifies whether the initial call to deserialize this object should create instances of the types (when true) or just plain objects (when false) -A callback can be provided for when a class is serialized and / or deserialized. To define the callback, add a static method `OnSerialized(instance : any, json : any)` to the class that needs custom post processing. Continuing with the Tree example from before, lets say your server expects a zero indexed roughness value but your front end needs to use a 1 based roughness. This can be handled with `OnSerialized` and `OnDeserialized` trivially. +```typescript + class CrewMember { -```typescript -class Bark { - public static OnSerialized(instance : Bark, json : any) : void { - json.roughness--; - } - - public static OnDeserialized(instance : Bark, json : any) : void { - instance.roughness++; - } -} + @autoserializeAs(String) firstName; + @autoserializeAs(String) lastName; + + static onDeserialized(data : JsonObject, instance : CrewMember, instantiationMethod : InstantiationMethod) { + instance.firstName = data.firstName.toLowerCase(); + instance.lastName = data.lastName.toLowerCase(); + } + + } ``` + ## Inheriting Serialization +Serialization behavior is not inherited by subclasses automatically. To inherit a base class's serialization / deserialization behavior, tag the subclass with `@inheritSerialization(ParentClass)`. -Serialization behavior is not inherited by subclasses automatically. To inherit a base class's serialization / deserialization behavior, tag the subclass with @inheritSerialization(ParentClass). ```typescript -import { inheritSerialization } from 'cerialize'; + import { inheritSerialization } from 'cerialize'; -@inheritSerialization(User) -class Admin extends User { + @inheritSerialization(User) + class Admin extends User { -} -``` -##Generics -Typescript generics unfortunately do not give any runtime type information, but they are still helpful in that you don not need to cast the output of a `Deserialize` function to a given type when the type can be inferred by the compiler. Cerialize supports generics through `GenericDeserialize` and `GenericDeserializeInto`. These two functions work exactly the same as their non generic counterparts but have a typed signature. -```typescript -import { GenericDeserialize, GenericDeserializeInto } from 'cerialize'; - -var tree = GenericDeserialize({value: "someValue"}, Tree); -expect((tree instanceof Tree)).toBe(true); -expect(tree.value).toBe("someValue"); - -var tree = new Tree(); -tree.value = 'hello'; -var tree2 = GenericDeserializeInto({value: "someValue"}, Tree, tree); -expect((tree2 instanceof Tree)).toBe(true); -expect(tree2).toBe(tree); -expect(tree.value).toBe("someValue"); + } ``` ## Customizing key transforms -Often your server and your client will have different property naming conventions. For instance, Rails / Ruby generally expects objects to have properties that are under_score_cased while most JS authors prefer camelCase. You can tell Cerialize to use a certain key transform automatically when serializing and deserializing by calling `DeserializeKeysFrom(transform : (key : string) => string)` and `SerializeKeysTo(transform : (key : string) => string)`. A handful of transform functions are provided in this package or you can define your own function conforming to `(key : string) => string`. -```typescript -import {SerializeKeysTo, DeserializeKeysFrom, UnderscoreCase} from 'cerialize'; -//CamelCase, UnderscoreCase, SnakeCase, and DashCase are provided -SerializeKeysTo(UnderscoreCase); -DeserializeKeysFrom(UnderscoreCase); -``` - -## Requirements +Often your server and your client will have different property naming conventions. For instance, Rails / Ruby generally expects objects to have properties that are under_score_cased while most JS authors prefer camelCase. You can tell Cerialize to use a certain key transform automatically when serializing and deserializing by calling `SetSerializeKeyTransform(fn : (str : string) => string)` and `SetDeserializeKeyTransform(fn : (str : string) => string)`. A handful of transform functions are provided in this package or you can define your own function conforming to `(key : string) => string`. +- The provided functions are: + - `CamelCase` + - `UnderscoreCase` + - `SnakeCase` + - `DashCase` -Cerialize uses the ES6 Map implementation so you must be on a browser that supports it or include a shim. +##### Note +When using `SetDeserializeKeyTransform(fn : (str : string) => string)` you need to provide a function that transforms the EXISTING keys to a format that allows indexing of the input object. +```typescript + //in this example we expect the server to give us upper cased key names + //we need to map our local camel cased key to match the server provided key + //NOT the other way around. + SetDeserializeKeyTransform(function (value : string) : string { + return value.toUpperCase(); + }); + + class Test { + @deserializeAs(String) value : string; + } + + const json = { + VALUE: "strvalue", + }; + + const instance = Deserialize(json, Test); + expect(instance).toEqual({ + value: "strvalue" + }); +``` diff --git a/dist/serialize.d.ts b/dist/serialize.d.ts deleted file mode 100644 index 5da8af9..0000000 --- a/dist/serialize.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -declare var TypeMap: any; -export declare type Serializer = (value: any) => any; -export declare type Deserializer = (value: any) => any; -export interface INewable { - new (...args: any[]): T; -} -export interface IEnum { - [enumeration: string]: any; -} -export interface ISerializable { - Serialize?: (value: any) => any; - Deserialize?: (json: any, instance?: any) => any; -} -export declare function CamelCase(str: string): string; -export declare function SnakeCase(str: string): string; -export declare function UnderscoreCase(str: string): string; -export declare function DashCase(str: string): string; -export declare function inheritSerialization(parentType: Function): any; -export declare function serialize(target: any, keyName: string): any; -export declare function deserialize(target: any, keyName: string): any; -export declare function autoserialize(target: any, keyName: string): any; -export declare function serializeAs(keyNameOrType: string | Serializer | INewable | ISerializable | IEnum, keyName?: string): any; -export declare function serializeIndexable(type: Serializer | INewable | ISerializable, keyName?: string): any; -export declare function deserializeAs(keyNameOrType: string | Function | INewable | ISerializable | IEnum, keyName?: string): any; -export declare function deserializeIndexable(type: Function | INewable | ISerializable, keyName?: string): any; -export declare function autoserializeAs(keyNameOrType: string | Function | INewable | ISerializable | IEnum, keyName?: string): any; -export declare function autoserializeIndexable(type: Function | INewable | ISerializable, keyName?: string): any; -export declare function Deserialize(json: any, type?: Function | INewable | ISerializable): any; -export declare function DeserializeInto(source: any, type: Function | INewable | ISerializable, target: any): any; -export declare function Serialize(instance: any, type?: Function | ISerializable): any; -export declare function GenericDeserialize(json: any, type: INewable): T; -export declare function GenericDeserializeInto(json: any, type: INewable, instance: T): T; -export declare function DeserializeKeysFrom(transform: (key: string) => string): void; -export declare function SerializeKeysTo(transform: (key: string) => string): void; -export declare function SerializableEnumeration(e: IEnum): void; -export { TypeMap as __TypeMap }; diff --git a/dist/serialize.js b/dist/serialize.js deleted file mode 100644 index 3461c6d..0000000 --- a/dist/serialize.js +++ /dev/null @@ -1,741 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -var win = null; -try { - win = window; -} -catch (e) { - win = global; -} -//some other modules might want access to the serialization meta data, expose it here -var TypeMap = win.__CerializeTypeMap = new win.Map(); -exports.__TypeMap = TypeMap; -//convert strings like my_camel_string to myCamelString -function CamelCase(str) { - var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); - return str.replace(STRING_CAMELIZE_REGEXP, function (match, separator, chr) { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function (match, separator, chr) { - return match.toLowerCase(); - }); -} -exports.CamelCase = CamelCase; -//convert strings like MyCamelString to my_camel_string -function SnakeCase(str) { - var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); - return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); -} -exports.SnakeCase = SnakeCase; -//convert strings like myCamelCase to my_camel_case -function UnderscoreCase(str) { - var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); - var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); - return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); -} -exports.UnderscoreCase = UnderscoreCase; -//convert strings like my_camelCase to my-camel-case -function DashCase(str) { - var STRING_DASHERIZE_REGEXP = (/([a-z\d])([A-Z])/g); - str = str.replace(/_/g, '-'); - return str.replace(STRING_DASHERIZE_REGEXP, '$1-$2').toLowerCase(); -} -exports.DashCase = DashCase; -function deserializeString(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; - } -} -function deserializeNumber(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return parseFloat(element); - }); - } - else { - return parseFloat(value); - } -} -function deserializeBoolean(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return Boolean(element); - }); - } - else { - return Boolean(value); - } -} -function serializeString(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; - } -} -function serializeNumber(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return parseInt(element); - }); - } - else { - return parseInt(value); - } -} -function serializeBoolean(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return Boolean(element); - }); - } - else { - return Boolean(value); - } -} -function getDeserializeFnForType(type) { - if (type === String) { - return deserializeString; - } - else if (type === Number) { - return deserializeNumber; - } - else if (type === Boolean) { - return deserializeBoolean; - } - else { - return type; - } -} -function getSerializeFnForType(type) { - if (type === String) { - return serializeString; - } - else if (type === Number) { - return serializeNumber; - } - else if (type === Boolean) { - return serializeBoolean; - } - else { - return type; - } -} -//gets meta data for a key name, creating a new meta data instance -//if the input array doesn't already define one for the given keyName -function getMetaData(array, keyName) { - for (var i = 0; i < array.length; i++) { - if (array[i].keyName === keyName) { - return array[i]; - } - } - array.push(new MetaData(keyName)); - return array[array.length - 1]; -} -//helper for grabbing the type and keyname from a multi-type input variable -function getTypeAndKeyName(keyNameOrType, keyName) { - var type = null; - var key = null; - if (typeof keyNameOrType === "string") { - key = keyNameOrType; - } - else if (keyNameOrType && typeof keyNameOrType === "function" || typeof keyNameOrType === "object") { - type = keyNameOrType; - key = keyName; - } - return { key: key, type: type }; -} -//todo instance.constructor.prototype.__proto__ === parent class, maybe use this? -//because types are stored in a JS Map keyed by constructor, serialization is not inherited by default -//keeping this seperate by default also allows sub classes to serialize differently than their parent -function inheritSerialization(parentType) { - return function (childType) { - var parentMetaData = TypeMap.get(parentType) || []; - var childMetaData = TypeMap.get(childType) || []; - for (var i = 0; i < parentMetaData.length; i++) { - var keyName = parentMetaData[i].keyName; - if (!MetaData.hasKeyName(childMetaData, keyName)) { - childMetaData.push(MetaData.clone(parentMetaData[i])); - } - } - TypeMap.set(childType, childMetaData); - }; -} -exports.inheritSerialization = inheritSerialization; -//an untyped serialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the serialization key for that type in the meta data -function serialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -exports.serialize = serialize; -//an untyped deserialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the deserialization key for that type in the meta data -function deserialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -exports.deserialize = deserialize; -//this combines @serialize and @deserialize as defined above -function autoserialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -exports.autoserialize = autoserialize; -//We dont actually need the type to serialize but I like the consistency with deserializeAs which definitely does -//serializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -function serializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var _a = getTypeAndKeyName(keyNameOrType, keyName), key = _a.key, type = _a.type; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (key) ? key : actualKeyName; - metadata.serializedType = type; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.serializeAs = serializeAs; -//Supports serializing of dictionary-like map objects, ie: { x: {}, y: {} } -function serializeIndexable(type, keyName) { - if (!type) - return; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (keyName) ? keyName : actualKeyName; - metadata.serializedType = type; - metadata.indexable = true; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.serializeIndexable = serializeIndexable; -//deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -function deserializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var _a = getTypeAndKeyName(keyNameOrType, keyName), key = _a.key, type = _a.type; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - //this allows the type to be a stand alone function instead of a class - //todo maybe add an explicit date and regexp deserialization function here - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.deserializeAs = deserializeAs; -//Supports deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -function deserializeIndexable(type, keyName) { - if (!type) - return; - var key = keyName; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.deserializeIndexable = deserializeIndexable; -//serializes and deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -function autoserializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var _a = getTypeAndKeyName(keyNameOrType, keyName), key = _a.key, type = _a.type; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.autoserializeAs = autoserializeAs; -//Supports serializing/deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -function autoserializeIndexable(type, keyName) { - if (!type) - return; - var key = keyName; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -exports.autoserializeIndexable = autoserializeIndexable; -//helper class to contain serialization meta data for a property, each property -//in a type tagged with a serialization annotation will contain an array of these -//objects each describing one property -var MetaData = (function () { - function MetaData(keyName) { - this.keyName = keyName; - this.serializedKey = null; - this.deserializedKey = null; - this.deserializedType = null; - this.serializedType = null; - this.indexable = false; - } - //checks for a key name in a meta data array - MetaData.hasKeyName = function (metadataArray, key) { - for (var i = 0; i < metadataArray.length; i++) { - if (metadataArray[i].keyName === key) - return true; - } - return false; - }; - //clone a meta data instance, used for inheriting serialization properties - MetaData.clone = function (data) { - var metadata = new MetaData(data.keyName); - metadata.deserializedKey = data.deserializedKey; - metadata.serializedKey = data.serializedKey; - metadata.serializedType = data.serializedType; - metadata.deserializedType = data.deserializedType; - metadata.indexable = data.indexable; - return metadata; - }; - return MetaData; -}()); -//merges two primitive objects recursively, overwriting or defining properties on -//`instance` as they defined in `json`. Works on objects, arrays and primitives -function mergePrimitiveObjects(instance, json) { - if (!json) - return instance; //if we dont have a json value, just use what the instance defines already - if (!instance) - return json; //if we dont have an instance value, just use the json - //for each key in the input json we need to do a merge into the instance object - Object.keys(json).forEach(function (key) { - var transformedKey = key; - if (typeof deserializeKeyTransform === "function") { - transformedKey = deserializeKeyTransform(key); - } - var jsonValue = json[key]; - var instanceValue = instance[key]; - if (Array.isArray(jsonValue)) { - //in the array case we reuse the items that exist already where possible - //so reset the instance array length (or make it an array if it isnt) - //then call mergePrimitiveObjects recursively - instanceValue = Array.isArray(instanceValue) ? instanceValue : []; - instanceValue.length = jsonValue.length; - for (var i = 0; i < instanceValue.length; i++) { - instanceValue[i] = mergePrimitiveObjects(instanceValue[i], jsonValue[i]); - } - } - else if (jsonValue && typeof jsonValue === "object") { - if (!instanceValue || typeof instanceValue !== "object") { - instanceValue = {}; - } - instanceValue = mergePrimitiveObjects(instanceValue, jsonValue); - } - else { - //primitive case, just use straight assignment - instanceValue = jsonValue; - } - instance[transformedKey] = instanceValue; - }); - return instance; -} -//takes an array defined in json and deserializes it into an array that ist stuffed with instances of `type`. -//any instances already defined in `arrayInstance` will be re-used where possible to maintain referential integrity. -function deserializeArrayInto(source, type, arrayInstance) { - if (!Array.isArray(arrayInstance)) { - arrayInstance = new Array(source.length); - } - //extend or truncate the target array to match the source array - arrayInstance.length = source.length; - for (var i = 0; i < source.length; i++) { - arrayInstance[i] = DeserializeInto(source[i], type, arrayInstance[i] || new type()); - } - return arrayInstance; -} -//takes an object defined in json and deserializes it into a `type` instance or populates / overwrites -//properties on `instance` if it is provided. -function deserializeObjectInto(json, type, instance) { - var metadataArray = TypeMap.get(type); - //if we dont have an instance we need to create a new `type` - if (instance === null || instance === void 0) { - if (type) { - instance = new type(); - } - } - //if we dont have any meta data and we dont have a type to inflate, just merge the objects - if (instance && !type && !metadataArray) { - return mergePrimitiveObjects(instance, json); - } - //if we dont have meta data just bail out and keep what we have - if (!metadataArray) { - invokeDeserializeHook(instance, json, type); - return instance; - } - //for each property in meta data, try to hydrate that property with its corresponding json value - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - //these are not the droids we're looking for (to deserialize), moving along - if (!metadata.deserializedKey) - continue; - var serializedKey = metadata.deserializedKey; - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - var source = json[serializedKey]; - if (source === void 0) - continue; - var keyName = metadata.keyName; - //if there is a custom deserialize function, use that - if (metadata.deserializedType && typeof metadata.deserializedType.Deserialize === "function") { - instance[keyName] = metadata.deserializedType.Deserialize(source); - } - else if (Array.isArray(source)) { - if (metadata.deserializedType) { - instance[keyName] = deserializeArrayInto(source, metadata.deserializedType, instance[keyName]); - } - else { - instance[keyName] = deserializeArray(source, null); - } - } - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - var deserializedDate = new Date(source); - if (instance[keyName] instanceof Date) { - instance[keyName].setTime(deserializedDate.getTime()); - } - else { - instance[keyName] = deserializedDate; - } - } - else if (typeof source === "string" && type === RegExp) { - instance[keyName] = new RegExp(source); - } - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObjectInto(source, metadata.deserializedType, instance[keyName]); - } - else { - instance[keyName] = deserializeObjectInto(source, metadata.deserializedType, instance[keyName]); - } - } - else { - instance[keyName] = source; - } - } - //invoke our after deserialized callback if provided - invokeDeserializeHook(instance, json, type); - return instance; -} -//deserializes a bit of json into a `type` -function Deserialize(json, type) { - if (Array.isArray(json)) { - return deserializeArray(json, type); - } - else if (json && typeof json === "object") { - return deserializeObject(json, type); - } - else if ((typeof json === "string" || json instanceof Date) && type === Date.prototype.constructor) { - return new Date(json); - } - else if (typeof json === "string" && type === RegExp) { - return new RegExp(json); - } - else { - return json; - } -} -exports.Deserialize = Deserialize; -//takes some json, a type, and a target object and deserializes the json into that object -function DeserializeInto(source, type, target) { - if (Array.isArray(source)) { - return deserializeArrayInto(source, type, target || []); - } - else if (source && typeof source === "object") { - return deserializeObjectInto(source, type, target || new type()); - } - else { - return target || (type && new type()) || null; - } -} -exports.DeserializeInto = DeserializeInto; -//deserializes an array of json into an array of `type` -function deserializeArray(source, type) { - var retn = new Array(source.length); - for (var i = 0; i < source.length; i++) { - retn[i] = Deserialize(source[i], type); - } - return retn; -} -function invokeDeserializeHook(instance, json, type) { - if (type && typeof (type).OnDeserialized === "function") { - type.OnDeserialized(instance, json); - } -} -function invokeSerializeHook(instance, json) { - if (typeof (instance.constructor).OnSerialized === "function") { - (instance.constructor).OnSerialized(instance, json); - } -} -//deserialize a bit of json into an instance of `type` -function deserializeObject(json, type) { - var metadataArray = TypeMap.get(type); - //if we dont have meta data, just decode the json and use that - if (!metadataArray) { - var inst = null; - if (!type) { - inst = JSON.parse(JSON.stringify(json)); - } - else { - inst = new type(); //todo this probably wrong - invokeDeserializeHook(inst, json, type); - } - return inst; - } - var instance = new type(); - //for each tagged property on the source type, try to deserialize it - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - if (!metadata.deserializedKey) - continue; - var serializedKey = metadata.deserializedKey; - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - var source = json[serializedKey]; - var keyName = metadata.keyName; - if (source === void 0) - continue; - if (source === null) { - instance[keyName] = source; - } - else if (metadata.deserializedType && typeof metadata.deserializedType.Deserialize === "function") { - instance[keyName] = metadata.deserializedType.Deserialize(source); - } - else if (Array.isArray(source)) { - instance[keyName] = deserializeArray(source, metadata.deserializedType || null); - } - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - instance[keyName] = new Date(source); - } - else if (typeof source === "string" && metadata.deserializedType === RegExp) { - instance[keyName] = new RegExp(json); - } - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObject(source, metadata.deserializedType); - } - else { - instance[keyName] = deserializeObject(source, metadata.deserializedType); - } - } - else { - instance[keyName] = source; - } - } - invokeDeserializeHook(instance, json, type); - return instance; -} -function deserializeIndexableObject(source, type) { - var retn = {}; - //todo apply key transformation here? - Object.keys(source).forEach(function (key) { - retn[key] = deserializeObject(source[key], type); - }); - return retn; -} -function deserializeIndexableObjectInto(source, type, instance) { - //todo apply key transformation here? - Object.keys(source).forEach(function (key) { - instance[key] = deserializeObjectInto(source[key], type, instance[key]); - }); - return instance; -} -//take an array and spit out json -function serializeArray(source, type) { - var serializedArray = new Array(source.length); - for (var j = 0; j < source.length; j++) { - serializedArray[j] = Serialize(source[j], type); - } - return serializedArray; -} -//take an instance of something and try to spit out json for it based on property annotaitons -function serializeTypedObject(instance, type) { - var json = {}; - var metadataArray; - if (type) { - metadataArray = TypeMap.get(type); - } - else { - metadataArray = TypeMap.get(instance.constructor); - } - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - if (!metadata.serializedKey) - continue; - var serializedKey = metadata.serializedKey; - if (metadata.serializedKey === metadata.keyName) { - if (typeof serializeKeyTransform === "function") { - serializedKey = serializeKeyTransform(metadata.keyName); - } - } - var source = instance[metadata.keyName]; - if (source === void 0) - continue; - if (Array.isArray(source)) { - json[serializedKey] = serializeArray(source, metadata.serializedType || null); - } - else if (metadata.serializedType && typeof metadata.serializedType.Serialize === "function") { - //todo -- serializeIndexableObject probably isn't needed because of how serialize works - json[serializedKey] = metadata.serializedType.Serialize(source); - } - else { - var value = Serialize(source); - if (value !== void 0) { - json[serializedKey] = value; - } - } - } - invokeSerializeHook(instance, json); - return json; -} -//take an instance of something and spit out some json -function Serialize(instance, type) { - if (instance === null || instance === void 0) - return null; - if (Array.isArray(instance)) { - return serializeArray(instance, type); - } - if (type && TypeMap.has(type)) { - return serializeTypedObject(instance, type); - } - if (instance.constructor && TypeMap.has(instance.constructor)) { - return serializeTypedObject(instance); - } - if (instance instanceof Date) { - return instance.toISOString(); - } - if (instance instanceof RegExp) { - return instance.toString(); - } - if (instance && typeof instance === 'object' || typeof instance === 'function') { - var keys = Object.keys(instance); - var json = {}; - for (var i = 0; i < keys.length; i++) { - //todo this probably needs a key transform - json[keys[i]] = Serialize(instance[keys[i]]); - } - invokeSerializeHook(instance, json); - return json; - } - return instance; -} -exports.Serialize = Serialize; -function GenericDeserialize(json, type) { - return Deserialize(json, type); -} -exports.GenericDeserialize = GenericDeserialize; -function GenericDeserializeInto(json, type, instance) { - return DeserializeInto(json, type, instance); -} -exports.GenericDeserializeInto = GenericDeserializeInto; -//these are used for transforming keys from one format to another -var serializeKeyTransform = null; -var deserializeKeyTransform = null; -//setter for deserializing key transform -function DeserializeKeysFrom(transform) { - deserializeKeyTransform = transform; -} -exports.DeserializeKeysFrom = DeserializeKeysFrom; -//setter for serializing key transform -function SerializeKeysTo(transform) { - serializeKeyTransform = transform; -} -exports.SerializeKeysTo = SerializeKeysTo; -//this is kinda dumb but typescript doesnt treat enums as a type, but sometimes you still -//want them to be serialized / deserialized, this does the trick but must be called after -//the enum is defined. -function SerializableEnumeration(e) { - e.Serialize = function (x) { - return e[x]; - }; - e.Deserialize = function (x) { - return e[x]; - }; -} -exports.SerializableEnumeration = SerializableEnumeration; diff --git a/dist/spec/autoserialize_annotation_spec.js b/dist/spec/autoserialize_annotation_spec.js deleted file mode 100644 index f702f84..0000000 --- a/dist/spec/autoserialize_annotation_spec.js +++ /dev/null @@ -1,187 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { __TypeMap, autoserialize, Serialize, Deserialize, DeserializeInto, autoserializeAs } from '../src/serialize'; -class T { -} -__decorate([ - autoserialize -], T.prototype, "x", void 0); -class Vector2 { -} -__decorate([ - autoserialize -], Vector2.prototype, "x", void 0); -__decorate([ - autoserialize -], Vector2.prototype, "y", void 0); -class AsTest { -} -__decorate([ - autoserializeAs(Vector2) -], AsTest.prototype, "v", void 0); -class AsTest2 { -} -__decorate([ - autoserializeAs(Vector2, "VECTOR") -], AsTest2.prototype, "v", void 0); -class AsTest3 { -} -__decorate([ - autoserializeAs("z") -], AsTest3.prototype, "y", void 0); -class Test3 { -} -__decorate([ - autoserialize -], Test3.prototype, "primitiveArray", void 0); -describe('autoserialize', function () { - it('should create meta data for serialize and deserialize', function () { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - }); -}); -describe('autoserializeAs', function () { - it('should create meta data', function () { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].serializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].serializedType).toBe(Vector2); - expect(__TypeMap.get(AsTest)[0].deserializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].deserializedType).toBe(Vector2); - }); - it('should create meta data with a different key', function () { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].serializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].serializedType).toBe(null); - expect(__TypeMap.get(AsTest3)[0].deserializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].deserializedType).toBe(null); - }); - it('should create meta data with a different key and type', function () { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].serializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].serializedType).toBe(Vector2); - expect(__TypeMap.get(AsTest2)[0].deserializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].deserializedType).toBe(Vector2); - }); - it("handles strings", function () { - }); -}); -var Utility; -(function (Utility) { - function unpackSet(_set) { - const result = []; - _set.forEach(v => result.push(v)); - return result; - } - Utility.unpackSet = unpackSet; -})(Utility || (Utility = {})); -describe('autoserializeAs using Serializer', () => { - describe('to wrapped data', () => { - const JSON = { - children: { - wrap: [11, 22, 33] - } - }; - const Serializer = { - Serialize(_set) { - return { wrap: Utility.unpackSet(_set) }; - }, - Deserialize(json, instance) { - return new Set(json.wrap); - } - }; - class TestClass { - constructor() { - this.children = new Set(); - } - } - __decorate([ - autoserializeAs(Serializer) - ], TestClass.prototype, "children", void 0); - it("will be serialized", () => { - const instance = new TestClass(); - JSON.children.wrap.forEach(v => instance.children.add(v)); - const json = Serialize(instance); - expect(json).toEqual(JSON); - }); - it("will be deserialized", () => { - const result = Deserialize(JSON, TestClass); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children.wrap); - }); - it("will be deserializedInto", () => { - const result = DeserializeInto(JSON, TestClass, new TestClass()); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children.wrap); - }); - }); - describe('should handle primitive arrays', function () { - it('should handle serializing a primitive array', function () { - var t = new Test3(); - t.primitiveArray = [1, 2, 3]; - var result = Serialize(t); - expect(result.primitiveArray.length).toBe(3); - expect(result.primitiveArray[0]).toBe(1); - expect(result.primitiveArray[1]).toBe(2); - expect(result.primitiveArray[2]).toBe(3); - }); - it('should handle deserializing a primitive array', function () { - var t = new Test3(); - t.primitiveArray = [1, 2, 3]; - var result = Deserialize({ primitiveArray: [1, 2, 3] }, Test3); - expect(Array.isArray(result.primitiveArray)).toBe(true); - }); - }); - describe('to plain array data', () => { - const JSON = { - children: [11, 22, 33] - }; - const Serializer = { - Serialize(_set) { - return Utility.unpackSet(_set); - }, - Deserialize(json, instance) { - return new Set(json); - } - }; - class TestClass { - constructor() { - this.children = new Set(); - } - } - __decorate([ - autoserializeAs(Serializer) - ], TestClass.prototype, "children", void 0); - it("will be serialized", () => { - const instance = new TestClass(); - JSON.children.forEach(v => instance.children.add(v)); - const json = Serialize(instance); - expect(json).toEqual(JSON); - }); - it("will be deserialized", () => { - const result = Deserialize(JSON, TestClass); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children); - }); - it("will be deserializedInto", () => { - const result = DeserializeInto(JSON, TestClass, new TestClass()); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children); - }); - }); -}); diff --git a/dist/spec/deserialize_annotation_spec.js b/dist/spec/deserialize_annotation_spec.js deleted file mode 100644 index 16c5096..0000000 --- a/dist/spec/deserialize_annotation_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { __TypeMap, deserialize, deserializeAs } from '../src/serialize'; -class T { -} -__decorate([ - deserialize -], T.prototype, "x", void 0); -class Vector2 { -} -__decorate([ - deserialize -], Vector2.prototype, "x", void 0); -__decorate([ - deserialize -], Vector2.prototype, "y", void 0); -class AsTest { -} -__decorate([ - deserializeAs(Vector2) -], AsTest.prototype, "v", void 0); -class AsTest2 { -} -__decorate([ - deserializeAs(Vector2, "VECTOR") -], AsTest2.prototype, "v", void 0); -class AsTest3 { -} -__decorate([ - deserializeAs("z") -], AsTest3.prototype, "y", void 0); -describe('deserialize', function () { - it('should create meta data', function () { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - }); -}); -describe('serializeAs', function () { - it('should create meta data', function () { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].deserializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].deserializedType).toBe(Vector2); - }); - it('should create meta data with a different key', function () { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].deserializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].deserializedType).toBe(null); - }); - it('should create meta data with a different key and type', function () { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].deserializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].deserializedType).toBe(Vector2); - }); -}); diff --git a/dist/spec/deserialize_function_spec.js b/dist/spec/deserialize_function_spec.js deleted file mode 100644 index 7dde025..0000000 --- a/dist/spec/deserialize_function_spec.js +++ /dev/null @@ -1,404 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { deserialize, deserializeAs, Deserialize, GenericDeserialize, GenericDeserializeInto, deserializeIndexable } from '../src/serialize'; -class T1 { -} -class T2 { - static OnDeserialized() { - } -} -__decorate([ - deserialize -], T2.prototype, "x", void 0); -__decorate([ - deserialize -], T2.prototype, "y", void 0); -class T3 { - static OnDeserialized() { - } -} -__decorate([ - deserializeAs(T2) -], T3.prototype, "child", void 0); -__decorate([ - deserialize -], T3.prototype, "x", void 0); -class T4 { -} -__decorate([ - deserializeAs(Date) -], T4.prototype, "dateList", void 0); -class T5 { -} -__decorate([ - deserializeAs(Date) -], T5.prototype, "date", void 0); -class JsonTest { - constructor() { - this.obj = { - key1: 1, - nestedKey: { - key2: 2 - } - }; - } -} -__decorate([ - deserialize -], JsonTest.prototype, "obj", void 0); -class Fruit { -} -__decorate([ - deserialize -], Fruit.prototype, "name", void 0); -class Tree { -} -__decorate([ - deserialize -], Tree.prototype, "value", void 0); -__decorate([ - deserializeAs(Fruit) -], Tree.prototype, "fruits", void 0); -__decorate([ - deserializeAs(Tree) -], Tree.prototype, "trees", void 0); -var DeserializerFn = function (src) { - return 'custom!'; -}; -var Deserializer = { - Deserialize: DeserializerFn -}; -class CustomDeserializeTest { -} -__decorate([ - deserializeAs(Deserializer) -], CustomDeserializeTest.prototype, "x", void 0); -class CustomDeserializeTest2 { -} -__decorate([ - deserializeAs(DeserializerFn) -], CustomDeserializeTest2.prototype, "x", void 0); -describe('Deserialize', function () { - it('should not deserialize if not marked with deserializer', function () { - var json = { x: 1, y: 2 }; - var instance = Deserialize(json, T1); - expect((instance instanceof T1)).toBe(true); - expect(instance.x).toBeUndefined(); - expect(instance.y).toBeUndefined(); - }); - it('should deserialize if marked with deserializer', function () { - var json = { x: 1, y: 2 }; - var instance = Deserialize(json, T2); - expect((instance instanceof T2)).toBe(true); - expect(instance.x).toBe(1); - expect(instance.y).toBe(2); - }); - it('should deserialize an array', function () { - var json = [{ x: 1, y: 1 }, { x: 2, y: 2 }]; - var list = Deserialize(json, T2); - expect(Array.isArray(list)); - expect(list.length).toBe(2); - expect(list[0] instanceof T2).toBe(true); - expect(list[0].x).toBe(1); - expect(list[0].y).toBe(1); - expect(list[1] instanceof T2).toBe(true); - expect(list[1].x).toBe(2); - expect(list[1].y).toBe(2); - }); - it('should deserialize a primitive', function () { - expect(Deserialize(1)).toBe(1); - expect(Deserialize(null)).toBe(null); - expect(Deserialize(false)).toBe(false); - expect(Deserialize(true)).toBe(true); - expect(Deserialize('1')).toBe('1'); - }); - it('should deserialize a date', function () { - var d = new Date(); - var dateStr = d.toString(); - var result = Deserialize(dateStr, Date); - expect(result instanceof Date).toBe(true); - }); - it('should deserialize a date even when it\'s not a string', function () { - var d = new Date(); - var result = Deserialize(d, Date); - expect(result instanceof Date).toBe(true); - expect(result.toString()).toEqual(d.toString()); - }); - it('should deserialize a regex', function () { - var r = /hi/; - var regexStr = r.toString(); - var result = Deserialize(regexStr, RegExp); - expect(result instanceof RegExp).toBe(true); - }); - it('should deserialize a nested object as a type', function () { - var t3 = { child: { x: 1, y: 1 }, x: 2 }; - var result = Deserialize(t3, T3); - expect(result instanceof T3).toBe(true); - expect(result.child instanceof T2).toBe(true); - expect(result.child.x).toBe(1); - expect(result.child.y).toBe(1); - expect(result.x).toBe(2); - }); - it('should deserialize a nested array as a type', function () { - var d1 = new Date(); - var d2 = new Date(); - var d3 = new Date(); - var t4 = { dateList: [d1.toString(), d2.toString(), d3] }; - var result = Deserialize(t4, T4); - expect(result instanceof T4).toBeTruthy(); - expect(Array.isArray(result.dateList)).toBe(true); - expect(result.dateList[0].toString()).toEqual(d1.toString()); - expect(result.dateList[1].toString()).toEqual(d2.toString()); - expect(result.dateList[2].toString()).toEqual(d3.toString()); - }); - it('should deserialize a Date property even if source is a Date object', function () { - var t5 = { date: new Date() }; - var result = Deserialize(t5, T5); - expect(result instanceof T5).toBeTruthy(); - expect(result.date.toString()).toEqual(t5.date.toString()); - }); - it('should call OnDeserialize if defined on parent and or child', function () { - var json = { - child: { x: 1, y: 1 }, - x: 10 - }; - spyOn(T3, 'OnDeserialized').and.callThrough(); - spyOn(T2, 'OnDeserialized').and.callThrough(); - var result = Deserialize(json, T3); - expect(T3.OnDeserialized).toHaveBeenCalledWith(result, json); - expect(T2.OnDeserialized).toHaveBeenCalledWith(result.child, json.child); - }); - it('should deserialize js objects tagged with deserialize', function () { - var testJson = new JsonTest(); - var result = Deserialize(testJson, JsonTest); - expect(result).toBeDefined(); - expect(typeof result.obj === "object").toBeTruthy(); - expect(result.obj.key1).toBe(1); - expect(result.obj.nestedKey.key2).toBe(2); - }); - it('should deserialize js primitive arrays tagged with deserialize', function () { - }); - it('should use a custom deserializer', function () { - var testJson = { - "x": new Date().toString() - }; - var result = Deserialize(testJson, CustomDeserializeTest); - expect(result.x).toBe("custom!"); - }); - it('should use a custom deserialize function', function () { - var testJson = { - "x": new Date().toString() - }; - var result = Deserialize(testJson, CustomDeserializeTest2); - expect(result.x).toBe("custom!"); - }); - it('should cast to primitive array when given a primitive type', function () { - class Test { - } - __decorate([ - deserializeAs(String) - ], Test.prototype, "arrayOfString", void 0); - __decorate([ - deserializeAs(Number) - ], Test.prototype, "arrayOfNumber", void 0); - __decorate([ - deserializeAs(Boolean) - ], Test.prototype, "arrayOfBoolean", void 0); - var json = { - arrayOfString: ['String1', 'String2'], - arrayOfNumber: [1, 2], - arrayOfBoolean: [true, false] - }; - var test = Deserialize(json, Test); - expect(Array.isArray(test.arrayOfString)).toBe(true); - expect(test.arrayOfString[0]).toBe("String1"); - expect(test.arrayOfString[1]).toBe("String2"); - expect(Array.isArray(test.arrayOfNumber)).toBe(true); - expect(test.arrayOfNumber[0]).toBe(1); - expect(test.arrayOfNumber[1]).toBe(2); - expect(Array.isArray(test.arrayOfBoolean)).toBe(true); - expect(test.arrayOfBoolean[0]).toBe(true); - expect(test.arrayOfBoolean[1]).toBe(false); - }); - it('should cast to primitive type when given a primitive type', function () { - class Test { - } - __decorate([ - deserializeAs(String) - ], Test.prototype, "str", void 0); - __decorate([ - deserializeAs(Number) - ], Test.prototype, "num", void 0); - __decorate([ - deserializeAs(Boolean) - ], Test.prototype, "bool", void 0); - __decorate([ - deserializeAs(Number) - ], Test.prototype, "float", void 0); - var json = { - str: 1, - num: "2", - bool: 3, - float: "3.1415" - }; - var test = Deserialize(json, Test); - expect(test.str).toBe('1'); - expect(test.num).toBe(2); - expect(test.bool).toBe(true); - expect(test.float).toBe(3.1415); - }); - //contributed by @1ambda - it('should deserialize a json including nested empty arrays', function () { - var root1 = { - trees: new Array(), - value: "root1" - }; - var deserialized1 = Deserialize(root1, Tree); - expect(deserialized1.trees.length).toBe(0); - expect(deserialized1.value).toBe("root1"); - /** - * `-- root - * |-- t1 - * `-- t2 - * |-- t3 - * `-- t4 - */ - var root2 = { - trees: [{ - value: "t1", - trees: new Array() - }, { - value: "t2", - trees: [{ - value: "t3", - trees: new Array() - }, { - value: "t4", - trees: new Array() - }] - }], - value: "root2" - }; - var deserialized2 = Deserialize(root2, Tree); - expect(deserialized2.trees.length).toBe(2); - expect(deserialized2.trees[0].trees.length).toBe(0); /* t1 includes empty trees */ - expect(deserialized2.trees[1].trees.length).toBe(2); /* t2 includes 2 trees (t3, t4) */ - }); - it("should deserialize custom objects into an array", function () { - // class Item { } - }); - it("should deserialize empty json into an empty string"); - it('should deserialize a json including nested, multiple empty arrays', function () { - var root1 = { - fruits: new Array(), - trees: new Array(), - value: "root1" - }; - var deserialized1 = Deserialize(root1, Tree); - expect(deserialized1.trees.length).toBe(0); - expect(deserialized1.value).toBe("root1"); - expect(deserialized1.fruits.length).toBe(0); - /** - * `-- root - * |-- t1 including f1 - * `-- t2 - * |-- t3 including f3 - * `-- t4 - */ - var root2 = { - trees: [{ - value: "t1", - trees: new Array(), - fruits: new Array(), - }, { - value: "t2", - trees: [{ - value: "t3", - trees: new Array(), - fruits: new Array(), - }, { - value: "t4", - trees: new Array() - }] - }], - value: "root2" - }; - var deserialized2 = Deserialize(root2, Tree); - expect(deserialized2.trees.length).toBe(2); - expect(deserialized2.trees[0].trees.length).toBe(0); /* t1 includes empty trees */ - expect(deserialized2.trees[0].fruits.length).toBe(0); /* t1 includes empty fruits */ - expect(deserialized2.trees[1].trees.length).toBe(2); /* t2 includes 2 trees (t3, t4) */ - expect(deserialized2.trees[1].trees[0].trees.length).toBe(0); /* t3 includes empty trees */ - expect(deserialized2.trees[1].trees[0].fruits.length).toBe(0); /* t3 includes fruits trees */ - expect(deserialized2.trees[1].trees[1].trees.length).toBe(0); /* t4 includes empty trees */ - expect(deserialized2.trees[1].trees[1].fruits).toBeUndefined(); /* t4 has no fruits */ - }); - it("Should deserialize indexable object", function () { - class Y { - } - __decorate([ - deserialize - ], Y.prototype, "thing", void 0); - class X { - } - __decorate([ - deserializeIndexable(Y) - ], X.prototype, "yMap", void 0); - var map = { - yMap: { - 1: { thing: '1' }, - 2: { thing: '2' } - } - }; - var x = Deserialize(map, X); - expect(x.yMap[1] instanceof (Y)).toBe(true); - expect(x.yMap[2] instanceof (Y)).toBe(true); - }); -}); -describe('Deserialize generics', function () { - it('should handle a generic deserialize', function () { - var tree = GenericDeserialize({ value: "someValue" }, Tree); - expect((tree instanceof Tree)).toBe(true); - expect(tree.value).toBe("someValue"); - }); - it('should handle a generic deserializeInto', function () { - var tree = new Tree(); - tree.value = 'hello'; - var tree2 = GenericDeserializeInto({ value: "someValue" }, Tree, tree); - expect((tree2 instanceof Tree)).toBe(true); - expect(tree2).toBe(tree); - expect(tree.value).toBe("someValue"); - }); -}); -export class Deserializable { - static deserialize(ctor, json) { - return Deserialize(json, ctor); - } - static deserializeArray(ctor, json) { - return Deserialize(json, ctor); - } -} -class Car extends Deserializable { -} -__decorate([ - deserialize -], Car.prototype, "engine", void 0); -__decorate([ - deserialize -], Car.prototype, "wheels", void 0); -describe("Deserializable", () => { - describe("deserialize", () => { - it("should parse Car", () => { - let json = { engine: "M5", wheels: 4 }; - let c1 = Car.deserialize(Car, json); - let c2 = Car.deserialize(Car, json); // without NoParamConstructor - expect(c1.engine).toEqual(json.engine); - expect(c1.wheels).toEqual(json.wheels); - }); - }); -}); diff --git a/dist/spec/deserialize_into_spec.js b/dist/spec/deserialize_into_spec.js deleted file mode 100644 index 894bf4a..0000000 --- a/dist/spec/deserialize_into_spec.js +++ /dev/null @@ -1,269 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { deserialize, deserializeAs, deserializeIndexable, autoserializeAs, DeserializeInto } from '../src/serialize'; -class T1 { -} -class T2 { - constructor(x, y) { - this.x = x; - this.y = y; - } -} -__decorate([ - deserialize -], T2.prototype, "x", void 0); -class T3 { - constructor(list) { - this.list = list; - } -} -__decorate([ - deserializeAs(T2) -], T3.prototype, "list", void 0); -class T4 { -} -__decorate([ - deserializeAs(T3, 'T3') -], T4.prototype, "t3", void 0); -__decorate([ - autoserializeAs(Date) -], T4.prototype, "date", void 0); -class JsonSubArrayTest { - constructor() { - this.obj = { - array: [{ x: 1 }, { x: 2 }] - }; - } -} -__decorate([ - deserialize -], JsonSubArrayTest.prototype, "obj", void 0); -class JSONSubObjectTest { - constructor() { - this.obj = { - subobject: { - a: 1, - b: 2 - } - }; - } -} -__decorate([ - deserialize -], JSONSubObjectTest.prototype, "obj", void 0); -class ArrayItem { - constructor(x) { - this.x = x; - } -} -__decorate([ - deserialize -], ArrayItem.prototype, "x", void 0); -class TypedNestedArrayTest { -} -__decorate([ - deserializeAs(ArrayItem) -], TypedNestedArrayTest.prototype, "children", void 0); -class NestedArrayTest { -} -__decorate([ - deserialize -], NestedArrayTest.prototype, "children", void 0); -class NestedArrayOfObjectsTest { -} -__decorate([ - deserialize -], NestedArrayOfObjectsTest.prototype, "children", void 0); -var CustomDeserializer = { - Deserialize: function (src) { - return 'custom!'; - } -}; -class CustomDeserialized { -} -__decorate([ - deserializeAs(CustomDeserializer) -], CustomDeserialized.prototype, "x", void 0); -describe('DeserializeInto', function () { - it('should return the same instance passed to it', function () { - var instance = new T1(); - expect(DeserializeInto({}, T1, instance)).toBe(instance); - }); - it('will create a new instance of Type if instance argument is null', function () { - expect(DeserializeInto({}, T1, null) instanceof T1).toBe(true); - }); - it('will deserialize into an array of Type if instance is an array', function () { - var instanceArray = []; - var result = DeserializeInto([{}, {}], T1, instanceArray); - expect(Array.isArray(result)).toBe(true); - expect(result.length).toBe(2); - expect(result[0] instanceof T1).toBe(true); - expect(result[1] instanceof T1).toBe(true); - }); - it('will only deserialized fields marked for deserialization', function () { - var json = { x: 10, y: 20 }; - var instance = new T2(1, 2); - var result = DeserializeInto(json, T2, instance); - expect(result.x).toBe(10); - expect(result.y).toBe(2); - }); - it('will deserialize an array property and preserve instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }, { x: 20, y: 20 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(2); - expect(instance.list[0]).toBe(test1); - expect(instance.list[1]).toBe(test2); - expect(test1.x).toBe(10); - expect(test1.y).toBe(1); - expect(test2.x).toBe(20); - expect(test2.y).toBe(2); - }); - it('will deserialize an array property and truncate instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(1); - expect(instance.list[0]).toBe(test1); - expect(test1.x).toBe(10); - expect(test1.y).toBe(1); - }); - it('will deserialize an array property and create instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }, { x: 20, y: 20 }, { x: 30, y: 30 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(3); - expect(instance.list[0]).toBe(test1); - expect(instance.list[1]).toBe(test2); - expect(instance.list[2] instanceof T2).toBe(true); - expect(originalList[2].x).toBe(30); - expect(originalList[2].y).toBe(void 0); - }); - it('will deserialize an object with nested deserialized properties', function () { - var instance = new T4(); - instance.t3 = new T3([]); - var d = new Date(); - instance.date = d; - var json = { - date: new Date().toString(), - T3: { - list: [{ x: 1 }, { x: 2 }] - } - }; - var result = DeserializeInto(json, T4, instance); - expect(result.t3.list[0].x).toBe(1); - expect(result.date).toBe(d); - }); - it('should deserialize arrays in untyped objects tagged with deserialize', function () { - var source = new JsonSubArrayTest(); - var json = { obj: { array: [{ x: 3 }, { x: 4 }, { x: 5 }] } }; - var result = DeserializeInto(json, JsonSubArrayTest, source); - expect(result).toEqual(source); - expect(result).toBeDefined(); - expect(typeof result.obj === "object").toBeTruthy(); - expect(result.obj.array.length).toBe(3); - expect(result.obj.array[0]).toEqual(source.obj.array[0]); - expect(result.obj.array[1]).toEqual(source.obj.array[1]); - expect(result.obj.array[0].x).toEqual(3); - expect(result.obj.array[1].x).toEqual(4); - expect(result.obj.array[2].x).toEqual(5); - }); - it('should deserialize sub-objects in untyped objects tagged with deserialize', function () { - var source = new JSONSubObjectTest(); - var originalSubObject = source.obj.subobject; - expect(source.obj.subobject.c).toBeUndefined(); - var json = { obj: { subobject: { a: 10, b: 20, c: 30 } } }; - var result = DeserializeInto(json, JSONSubObjectTest, source); - expect(result).toEqual(source); - expect(result.obj.subobject).toEqual(originalSubObject); - expect(result.obj.subobject.a).toEqual(10); - expect(result.obj.subobject.b).toEqual(20); - expect(result.obj.subobject.c).toEqual(30); - }); - it('should deserialize with a custom deserializer', function () { - var testJson = { - "x": new Date().toString() - }; - var result = DeserializeInto(testJson, CustomDeserialized, null); - expect(result.x).toBe("custom!"); - }); - it('will deserialize js nested primitive array tagged with deserialize', function () { - var json = { children: ["1", "2", "3", "4"] }; - var result = DeserializeInto(json, NestedArrayTest, new NestedArrayTest()); - expect(result.children).toEqual(["1", "2", "3", "4"]); - expect(result instanceof NestedArrayTest).toBe(true); - }); - it('will deserialize nested non primitive array tagged with deserialize', function () { - var json = { children: [{ x: "1" }, { x: "2" }, { x: "3" }, { x: "4" }] }; - var result = DeserializeInto(json, TypedNestedArrayTest, new TypedNestedArrayTest()); - expect(result.children[0].x).toEqual("1"); - expect(result.children[1].x).toEqual("2"); - expect(result.children[2].x).toEqual("3"); - expect(result.children[3].x).toEqual("4"); - expect(result.children[0] instanceof ArrayItem).toBe(true); - expect(result.children[1] instanceof ArrayItem).toBe(true); - expect(result.children[2] instanceof ArrayItem).toBe(true); - expect(result.children[3] instanceof ArrayItem).toBe(true); - }); - it("will deserialized neseted object array tagged with deserialize", function () { - var original = new NestedArrayOfObjectsTest(); - original.children = [{ x: "10" }, { x: "20" }, { x: "30" }]; - var json = { children: [{ x: "1" }, { x: "2" }, { x: "3" }, { x: "4" }] }; - var result = DeserializeInto(json, NestedArrayOfObjectsTest, new NestedArrayOfObjectsTest()); - expect(result.children.length).toEqual(4); - expect(result.children[0].x).toEqual("1"); - expect(result.children[1].x).toEqual("2"); - expect(result.children[2].x).toEqual("3"); - expect(result.children[3].x).toEqual("4"); - }); - it("Should deserialize indexable object", function () { - class Y { - } - __decorate([ - deserialize - ], Y.prototype, "thing", void 0); - class X { - constructor() { - this.yMap = {}; - } - } - __decorate([ - deserializeIndexable(Y) - ], X.prototype, "yMap", void 0); - var map = { - yMap: { - 1: { thing: '1' }, - 2: { thing: '2' } - } - }; - var x = new X(); - var yMap = x.yMap; - DeserializeInto(map, X, x); - expect(x.yMap).toBe(yMap); - expect(x.yMap[1] instanceof (Y)).toBe(true); - expect(x.yMap[2] instanceof (Y)).toBe(true); - }); -}); diff --git a/dist/spec/enum_spec.js b/dist/spec/enum_spec.js deleted file mode 100644 index 82759f7..0000000 --- a/dist/spec/enum_spec.js +++ /dev/null @@ -1,44 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { autoserializeAs, Serialize, Deserialize, DeserializeInto, SerializableEnumeration } from '../src/serialize'; -var TestEnum; -(function (TestEnum) { - TestEnum[TestEnum["One"] = 1] = "One"; - TestEnum[TestEnum["Two"] = 2] = "Two"; - TestEnum[TestEnum["Three"] = 4] = "Three"; -})(TestEnum || (TestEnum = {})); -SerializableEnumeration(TestEnum); -class T1 { -} -__decorate([ - autoserializeAs(TestEnum) -], T1.prototype, "e", void 0); -describe('Enums', function () { - it('should serialize an enum', function () { - var t1 = new T1(); - t1.e = TestEnum.One; - var result = Serialize(t1); - expect(result.e).toBe("One"); - }); - it('should deserialize an enum', function () { - var json = { - e: "One" - }; - var result = Deserialize(json, T1); - expect(result.e).toBe(TestEnum.One); - }); - it('should deserializeInto an enum', function () { - var json = { - e: "One" - }; - var t1 = new T1(); - var result = DeserializeInto(json, T1, t1); - expect(result.e).toBe(TestEnum.One); - expect(result).toBe(t1); - }); -}); diff --git a/dist/spec/hook_spec.js b/dist/spec/hook_spec.js deleted file mode 100644 index 928c683..0000000 --- a/dist/spec/hook_spec.js +++ /dev/null @@ -1,25 +0,0 @@ -import { Serialize, Deserialize, DeserializeInto } from '../src/serialize'; -class HookTest { - static OnDeserialized(instance, json) { } - static OnSerialized(instance, json) { } -} -describe("OnDeserialized hooks", function () { - it("should always call OnDeserialized with Deserialize", function () { - var x = { hello: 'Guten Tag' }; - spyOn(HookTest, 'OnDeserialized'); - var inst = Deserialize(x, HookTest); - expect(HookTest.OnDeserialized).toHaveBeenCalledWith(inst, x); - }); - it("should always call OnDeserialized with DeserializeInto", function () { - var x = { hello: 'Guten Tag' }; - spyOn(HookTest, 'OnDeserialized'); - var inst = DeserializeInto(x, HookTest, new HookTest()); - expect(HookTest.OnDeserialized).toHaveBeenCalledWith(inst, x); - }); - it("should always call OnSerialized with Serialize", function () { - var inst = new HookTest(); - spyOn(HookTest, 'OnSerialized'); - var json = Serialize(inst); - expect(HookTest.OnSerialized).toHaveBeenCalledWith(inst, json); - }); -}); diff --git a/dist/spec/inherit_serialization_spec.js b/dist/spec/inherit_serialization_spec.js deleted file mode 100644 index ad0bb73..0000000 --- a/dist/spec/inherit_serialization_spec.js +++ /dev/null @@ -1,52 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { Serialize, Deserialize, serialize, serializeAs, deserializeAs, deserialize, inheritSerialization } from '../src/serialize'; -class T { -} -__decorate([ - serialize -], T.prototype, "x", void 0); -__decorate([ - serializeAs('Y') -], T.prototype, "y", void 0); -__decorate([ - deserialize -], T.prototype, "dX", void 0); -__decorate([ - deserializeAs('DY') -], T.prototype, "dY", void 0); -let ExtendedT = class ExtendedT extends T { -}; -__decorate([ - serialize -], ExtendedT.prototype, "z", void 0); -__decorate([ - deserialize -], ExtendedT.prototype, "dZ", void 0); -ExtendedT = __decorate([ - inheritSerialization(T) -], ExtendedT); -describe('Inherit Serialization', function () { - it('should inherit serialized properties from a class', function () { - var instance = new ExtendedT(); - instance.x = 1; - instance.y = 2; - instance.z = 3; - var result = Serialize(instance); - expect(result.x).toBe(1); - expect(result.Y).toBe(2); - expect(result.z).toBe(3); - }); - it('should inherit deserialized properties from a class', function () { - var json = { dX: 1, DY: 2, dZ: 3 }; - var instance = Deserialize(json, ExtendedT); - expect(instance.dX).toBe(1); - expect(instance.dY).toBe(2); - expect(instance.dZ).toBe(3); - }); -}); diff --git a/dist/spec/key_transform_spec.js b/dist/spec/key_transform_spec.js deleted file mode 100644 index ec2df48..0000000 --- a/dist/spec/key_transform_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { autoserialize, autoserializeAs, DeserializeInto, DeserializeKeysFrom, SerializeKeysTo, Serialize, Deserialize, CamelCase, UnderscoreCase } from '../src/serialize'; -class T1 { -} -__decorate([ - autoserialize -], T1.prototype, "myVar", void 0); -__decorate([ - autoserializeAs('something-else') -], T1.prototype, "other", void 0); -describe('Key Transforms', function () { - afterEach(function () { - DeserializeKeysFrom(CamelCase); - SerializeKeysTo(CamelCase); - }); - it('should just clone key name if no transform functions are set', function () { - SerializeKeysTo(null); - DeserializeKeysFrom(null); - var t1 = new T1(); - t1.myVar = 10; - t1.other = 11; - var result = Serialize(t1); - expect(result['something-else']).toBe(11); - expect(result.myVar).toBe(10); - var result = Deserialize({ - myVar: 10, - 'something-else': 11 - }, T1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - }); - it('should transform keys if serializedKeyTransform is set', function () { - SerializeKeysTo(UnderscoreCase); - var t1 = new T1(); - t1.myVar = 10; - t1.other = 11; - var result = Serialize(t1); - expect(result['something-else']).toBe(11); - expect(result.my_var).toBe(10); - }); - it('should transform keys if deserializedKeyTransform is set', function () { - DeserializeKeysFrom(UnderscoreCase); - var result = Deserialize({ - my_var: 10, - 'something-else': 11 - }, T1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - var t1 = new T1(); - result = DeserializeInto({ - my_var: 10, - 'something-else': 11 - }, T1, t1); - expect(result).toBe(t1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - }); -}); diff --git a/dist/spec/mixed_annotations_spec.js b/dist/spec/mixed_annotations_spec.js deleted file mode 100644 index d9929d6..0000000 --- a/dist/spec/mixed_annotations_spec.js +++ /dev/null @@ -1,59 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { __TypeMap, Serialize, Deserialize, serialize, serializeAs, deserializeAs, deserialize } from '../src/serialize'; -class T { -} -__decorate([ - serialize, - deserialize -], T.prototype, "x", void 0); -class T2 { -} -__decorate([ - serializeAs('X'), - deserializeAs('_X_') -], T2.prototype, "x", void 0); -class T3 { -} -__decorate([ - serializeAs(T), - deserializeAs(T2) -], T3.prototype, "t", void 0); -describe('Mixed annotations', function () { - it('should create meta data for serialize and deserialize', function () { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - }); - it('can serialize and deserialize with different keys', function () { - var json = { '_X_': 10 }; - var instance = new T2(); - instance.x = 20; - var serialized = Serialize(instance); - var deserialized = Deserialize(json, T2); - expect(serialized.X).toBe(20); - expect(serialized.x).toBeUndefined(); - expect(deserialized.x).toBe(10); - expect(deserialized._X_).toBeUndefined(); - }); - it('can serialize and deserialize with different types', function () { - var json = { t: { '_X_': 10 } }; - var instance = new T3(); - instance.t = new T(); - instance.t.x = 20; - var serialized = Serialize(instance); - var deserialized = Deserialize(json, T3); - expect(serialized.t.x).toBe(20); - expect(serialized.x).toBeUndefined(); - expect(deserialized.t instanceof T2).toBe(true); - expect(deserialized.t.x).toBe(10); - }); -}); diff --git a/dist/spec/serialize_annotation_spec.js b/dist/spec/serialize_annotation_spec.js deleted file mode 100644 index fb927b9..0000000 --- a/dist/spec/serialize_annotation_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { __TypeMap, serialize, serializeAs } from '../src/serialize'; -class T { -} -__decorate([ - serialize -], T.prototype, "x", void 0); -class Vector2 { -} -__decorate([ - serialize -], Vector2.prototype, "x", void 0); -__decorate([ - serialize -], Vector2.prototype, "y", void 0); -class AsTest { -} -__decorate([ - serializeAs(Vector2) -], AsTest.prototype, "v", void 0); -class AsTest2 { -} -__decorate([ - serializeAs(Vector2, "VECTOR") -], AsTest2.prototype, "v", void 0); -class AsTest3 { -} -__decorate([ - serializeAs("z") -], AsTest3.prototype, "y", void 0); -describe('serialize', function () { - it('should create meta data', function () { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - }); -}); -describe('serializeAs', function () { - it('should create meta data', function () { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].serializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].serializedType).toBe(Vector2); - }); - it('should create meta data with a different key', function () { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].serializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].serializedType).toBe(null); - }); - it('should create meta data with a different key and type', function () { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].serializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].serializedType).toBe(Vector2); - }); -}); diff --git a/dist/spec/serialize_function_spec.js b/dist/spec/serialize_function_spec.js deleted file mode 100644 index dd70623..0000000 --- a/dist/spec/serialize_function_spec.js +++ /dev/null @@ -1,217 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -}; -/// -import { serialize, serializeAs, Serialize, serializeIndexable } from '../src/serialize'; -class Vector3 { - constructor(x, y) { - this.x = x; - this.y = y; - this.z = 100; - } -} -__decorate([ - serialize -], Vector3.prototype, "x", void 0); -__decorate([ - serialize -], Vector3.prototype, "y", void 0); -class TArray { - constructor(x, y, points) { - this.x = x; - this.y = y; - this.z = 100; - this.points = points; - } -} -__decorate([ - serialize -], TArray.prototype, "x", void 0); -__decorate([ - serialize -], TArray.prototype, "y", void 0); -__decorate([ - serializeAs(Vector3) -], TArray.prototype, "points", void 0); -class TSubObject { - constructor() { - this.v1 = new Vector3(1, 2); - this.v2 = new Vector3(2, 1); - } - static OnSerialized(instance, json) { - //do nothing - } -} -__decorate([ - serializeAs(Vector3, 'specialKey') -], TSubObject.prototype, "v1", void 0); -__decorate([ - serializeAs(Vector3) -], TSubObject.prototype, "v2", void 0); -var SerializeFn = function (src) { - return 'custom!'; -}; -var CustomerSerialized = { - Serialize: SerializeFn -}; -class CustomSerializedTest { -} -__decorate([ - serializeAs(CustomerSerialized) -], CustomSerializedTest.prototype, "x", void 0); -class CustomSerializedTest2 { -} -__decorate([ - serializeAs(SerializeFn) -], CustomSerializedTest2.prototype, "x", void 0); -describe('Serialize', function () { - it('should serialize a primitive', function () { - expect(Serialize(5)).toBe(5); - expect(Serialize(true)).toBe(true); - expect(Serialize(undefined)).toBe(null); - expect(Serialize(null)).toBe(null); - expect(Serialize("string")).toBe("string"); - }); - it('should stringify a date', function () { - var d = new Date(); - expect(Serialize(d)).toBe(d.toISOString()); - }); - it('should stringify a regex', function () { - var reg = /hi/; - expect(Serialize(reg)).toBe(reg.toString()); - }); - it('should serialize 0', function () { - expect(Serialize(0)).toBe(0); - }); - it('should serialize false', function () { - expect(Serialize(false)).toBe(false); - }); - it('should seralize an untyped object', function () { - var obj = { one: 1, yep: true, now: new Date() }; - var serialized = Serialize(obj); - expect(serialized).not.toBe(obj); - expect(serialized.one).toBe(1); - expect(serialized.yep).toBe(true); - expect(serialized.now).toBe(obj.now.toISOString()); - }); - it('should serialize a nested untyped object', function () { - var obj = { - one: 1, yep: true, now: new Date(), child: { - childOne: 1, childTwo: 2 - } - }; - var serialized = Serialize(obj); - expect(serialized.child.childOne).toBe(1); - expect(serialized.child.childTwo).toBe(2); - }); - it('should serialize an untyped array', function () { - var array = [{ one: 1 }, { two: 2 }, { three: 3 }]; - var serialized = Serialize(array); - expect(Array.isArray(serialized)).toBe(true); - expect(serialized.length).toBe(3); - expect(serialized[0]).not.toBe(array[0]); - expect(serialized[0].one).toBe(1); - expect(serialized[1]).not.toBe(array[1]); - expect(serialized[1].two).toBe(2); - expect(serialized[2]).not.toBe(array[2]); - expect(serialized[2].three).toBe(3); - }); - it('should serialize a typed object', function () { - var test = new Vector3(1, 2); - var serialized = Serialize(test); - expect((serialized instanceof Vector3)).toBe(false); - expect(serialized.x).toBe(test.x); - expect(serialized.y).toBe(test.y); - expect(serialized.z).toBe(void 0); - }); - it('should serialize object with the given type', function () { - var test = { x: 1, y: 2, z: 3 }; - var serialized = Serialize(test, Vector3); - expect((serialized instanceof Vector3)).toBe(false); - expect(serialized.x).toBe(test.x); - expect(serialized.y).toBe(test.y); - expect(serialized.z).toBe(void 0); - }); - it('should serialize a typed object with a typed array', function () { - var test = new TArray(10, 11, [new Vector3(1, 2), new Vector3(2, 1)]); - var serialized = Serialize(test); - expect(serialized.points).toBeDefined(); - expect(Array.isArray(serialized.points)).toBe(true); - expect(serialized.points.length).toBe(2); - expect(serialized.points[0].x).toBe(1); - expect(serialized.points[0].y).toBe(2); - expect(serialized.points[0].z).toBe(void 0); - expect(serialized.points[1].x).toBe(2); - expect(serialized.points[1].y).toBe(1); - expect(serialized.points[1].z).toBe(void 0); - expect(serialized.x).toBe(10); - expect(serialized.y).toBe(11); - expect(Object.keys(serialized).length).toBe(3); - }); - it('should serialize a typed object with typed subobjects', function () { - var test = new TSubObject(); - var serialized = Serialize(test); - expect(serialized.specialKey).toBeDefined(); - expect(serialized.specialKey.x).toBe(1); - expect(serialized.specialKey.y).toBe(2); - expect(serialized.specialKey.z).toBe(void 0); - expect(serialized.v2).toBeDefined(); - expect(serialized.v2.x).toBe(2); - expect(serialized.v2.y).toBe(1); - expect(serialized.v2.z).toBe(void 0); - }); - it('will call OnSerialized if a type defines it', function () { - var test = new TSubObject(); - spyOn(TSubObject, 'OnSerialized').and.callThrough(); - var json = Serialize(test); - expect(TSubObject.OnSerialized).toHaveBeenCalledWith(test, json); - }); - it('should use a custom serializer', function () { - var test = new CustomSerializedTest(); - test.x = 'not custom'; - var result = Serialize(test); - expect(result.x).toBe('custom!'); - }); - it('should use a custom serialize fn', function () { - var test = new CustomSerializedTest2(); - test.x = 'not custom'; - var result = Serialize(test); - expect(result.x).toBe('custom!'); - }); - it('should serialize indexable objects', function () { - class Y { - constructor(str) { - this.thing = str; - } - } - __decorate([ - serialize - ], Y.prototype, "thing", void 0); - class X { - } - __decorate([ - serializeIndexable(Y) - ], X.prototype, "yMap", void 0); - var x = new X(); - x.yMap = { - 1: new Y('one'), - 2: new Y('two') - }; - var json = Serialize(x); - expect(json.yMap[1].thing).toBe('one'); - expect(json.yMap[2].thing).toBe('two'); - }); - // it("should apply custom names recursively", function() { - // class Person { - // @serializeAs(Person, 'Girl_Friend') - // public girlFriend : Person; - // } - // var instance = new Person(); - // instance.girlFriend = new Person(); - // instance.girlFriend.girlFriend = new Person(); - // var json = Serialize(instance, Person); - // }) -}); diff --git a/dist/src/serialize.js b/dist/src/serialize.js deleted file mode 100644 index 6c40688..0000000 --- a/dist/src/serialize.js +++ /dev/null @@ -1,717 +0,0 @@ -var win = null; -try { - win = window; -} -catch (e) { - win = global; -} -//some other modules might want access to the serialization meta data, expose it here -var TypeMap = win.__CerializeTypeMap = new win.Map(); -//convert strings like my_camel_string to myCamelString -export function CamelCase(str) { - var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); - return str.replace(STRING_CAMELIZE_REGEXP, function (match, separator, chr) { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function (match, separator, chr) { - return match.toLowerCase(); - }); -} -//convert strings like MyCamelString to my_camel_string -export function SnakeCase(str) { - var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); - return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); -} -//convert strings like myCamelCase to my_camel_case -export function UnderscoreCase(str) { - var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); - var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); - return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); -} -//convert strings like my_camelCase to my-camel-case -export function DashCase(str) { - var STRING_DASHERIZE_REGEXP = (/([a-z\d])([A-Z])/g); - str = str.replace(/_/g, '-'); - return str.replace(STRING_DASHERIZE_REGEXP, '$1-$2').toLowerCase(); -} -function deserializeString(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; - } -} -function deserializeNumber(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return parseFloat(element); - }); - } - else { - return parseFloat(value); - } -} -function deserializeBoolean(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return Boolean(element); - }); - } - else { - return Boolean(value); - } -} -function serializeString(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; - } -} -function serializeNumber(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return parseInt(element); - }); - } - else { - return parseInt(value); - } -} -function serializeBoolean(value) { - if (Array.isArray(value)) { - return value.map(function (element) { - return Boolean(element); - }); - } - else { - return Boolean(value); - } -} -function getDeserializeFnForType(type) { - if (type === String) { - return deserializeString; - } - else if (type === Number) { - return deserializeNumber; - } - else if (type === Boolean) { - return deserializeBoolean; - } - else { - return type; - } -} -function getSerializeFnForType(type) { - if (type === String) { - return serializeString; - } - else if (type === Number) { - return serializeNumber; - } - else if (type === Boolean) { - return serializeBoolean; - } - else { - return type; - } -} -//gets meta data for a key name, creating a new meta data instance -//if the input array doesn't already define one for the given keyName -function getMetaData(array, keyName) { - for (var i = 0; i < array.length; i++) { - if (array[i].keyName === keyName) { - return array[i]; - } - } - array.push(new MetaData(keyName)); - return array[array.length - 1]; -} -//helper for grabbing the type and keyname from a multi-type input variable -function getTypeAndKeyName(keyNameOrType, keyName) { - var type = null; - var key = null; - if (typeof keyNameOrType === "string") { - key = keyNameOrType; - } - else if (keyNameOrType && typeof keyNameOrType === "function" || typeof keyNameOrType === "object") { - type = keyNameOrType; - key = keyName; - } - return { key: key, type: type }; -} -//todo instance.constructor.prototype.__proto__ === parent class, maybe use this? -//because types are stored in a JS Map keyed by constructor, serialization is not inherited by default -//keeping this seperate by default also allows sub classes to serialize differently than their parent -export function inheritSerialization(parentType) { - return function (childType) { - var parentMetaData = TypeMap.get(parentType) || []; - var childMetaData = TypeMap.get(childType) || []; - for (var i = 0; i < parentMetaData.length; i++) { - var keyName = parentMetaData[i].keyName; - if (!MetaData.hasKeyName(childMetaData, keyName)) { - childMetaData.push(MetaData.clone(parentMetaData[i])); - } - } - TypeMap.set(childType, childMetaData); - }; -} -//an untyped serialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the serialization key for that type in the meta data -export function serialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -//an untyped deserialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the deserialization key for that type in the meta data -export function deserialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -//this combines @serialize and @deserialize as defined above -export function autoserialize(target, keyName) { - if (!target || !keyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} -//We dont actually need the type to serialize but I like the consistency with deserializeAs which definitely does -//serializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function serializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var { key, type } = getTypeAndKeyName(keyNameOrType, keyName); - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (key) ? key : actualKeyName; - metadata.serializedType = type; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//Supports serializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function serializeIndexable(type, keyName) { - if (!type) - return; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (keyName) ? keyName : actualKeyName; - metadata.serializedType = type; - metadata.indexable = true; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function deserializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var { key, type } = getTypeAndKeyName(keyNameOrType, keyName); - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - //this allows the type to be a stand alone function instead of a class - //todo maybe add an explicit date and regexp deserialization function here - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//Supports deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function deserializeIndexable(type, keyName) { - if (!type) - return; - var key = keyName; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//serializes and deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function autoserializeAs(keyNameOrType, keyName) { - if (!keyNameOrType) - return; - var { key, type } = getTypeAndKeyName(keyNameOrType, keyName); - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//Supports serializing/deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function autoserializeIndexable(type, keyName) { - if (!type) - return; - var key = keyName; - return function (target, actualKeyName) { - if (!target || !actualKeyName) - return; - var metaDataList = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} -//helper class to contain serialization meta data for a property, each property -//in a type tagged with a serialization annotation will contain an array of these -//objects each describing one property -class MetaData { - constructor(keyName) { - this.keyName = keyName; - this.serializedKey = null; - this.deserializedKey = null; - this.deserializedType = null; - this.serializedType = null; - this.indexable = false; - } - //checks for a key name in a meta data array - static hasKeyName(metadataArray, key) { - for (var i = 0; i < metadataArray.length; i++) { - if (metadataArray[i].keyName === key) - return true; - } - return false; - } - //clone a meta data instance, used for inheriting serialization properties - static clone(data) { - var metadata = new MetaData(data.keyName); - metadata.deserializedKey = data.deserializedKey; - metadata.serializedKey = data.serializedKey; - metadata.serializedType = data.serializedType; - metadata.deserializedType = data.deserializedType; - metadata.indexable = data.indexable; - return metadata; - } -} -//merges two primitive objects recursively, overwriting or defining properties on -//`instance` as they defined in `json`. Works on objects, arrays and primitives -function mergePrimitiveObjects(instance, json) { - if (!json) - return instance; //if we dont have a json value, just use what the instance defines already - if (!instance) - return json; //if we dont have an instance value, just use the json - //for each key in the input json we need to do a merge into the instance object - Object.keys(json).forEach(function (key) { - var transformedKey = key; - if (typeof deserializeKeyTransform === "function") { - transformedKey = deserializeKeyTransform(key); - } - var jsonValue = json[key]; - var instanceValue = instance[key]; - if (Array.isArray(jsonValue)) { - //in the array case we reuse the items that exist already where possible - //so reset the instance array length (or make it an array if it isnt) - //then call mergePrimitiveObjects recursively - instanceValue = Array.isArray(instanceValue) ? instanceValue : []; - instanceValue.length = jsonValue.length; - for (var i = 0; i < instanceValue.length; i++) { - instanceValue[i] = mergePrimitiveObjects(instanceValue[i], jsonValue[i]); - } - } - else if (jsonValue && typeof jsonValue === "object") { - if (!instanceValue || typeof instanceValue !== "object") { - instanceValue = {}; - } - instanceValue = mergePrimitiveObjects(instanceValue, jsonValue); - } - else { - //primitive case, just use straight assignment - instanceValue = jsonValue; - } - instance[transformedKey] = instanceValue; - }); - return instance; -} -//takes an array defined in json and deserializes it into an array that ist stuffed with instances of `type`. -//any instances already defined in `arrayInstance` will be re-used where possible to maintain referential integrity. -function deserializeArrayInto(source, type, arrayInstance) { - if (!Array.isArray(arrayInstance)) { - arrayInstance = new Array(source.length); - } - //extend or truncate the target array to match the source array - arrayInstance.length = source.length; - for (var i = 0; i < source.length; i++) { - arrayInstance[i] = DeserializeInto(source[i], type, arrayInstance[i] || new type()); - } - return arrayInstance; -} -//takes an object defined in json and deserializes it into a `type` instance or populates / overwrites -//properties on `instance` if it is provided. -function deserializeObjectInto(json, type, instance) { - var metadataArray = TypeMap.get(type); - //if we dont have an instance we need to create a new `type` - if (instance === null || instance === void 0) { - if (type) { - instance = new type(); - } - } - //if we dont have any meta data and we dont have a type to inflate, just merge the objects - if (instance && !type && !metadataArray) { - return mergePrimitiveObjects(instance, json); - } - //if we dont have meta data just bail out and keep what we have - if (!metadataArray) { - invokeDeserializeHook(instance, json, type); - return instance; - } - //for each property in meta data, try to hydrate that property with its corresponding json value - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - //these are not the droids we're looking for (to deserialize), moving along - if (!metadata.deserializedKey) - continue; - var serializedKey = metadata.deserializedKey; - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - var source = json[serializedKey]; - if (source === void 0) - continue; - var keyName = metadata.keyName; - //if there is a custom deserialize function, use that - if (metadata.deserializedType && typeof metadata.deserializedType.Deserialize === "function") { - instance[keyName] = metadata.deserializedType.Deserialize(source); - } - else if (Array.isArray(source)) { - if (metadata.deserializedType) { - instance[keyName] = deserializeArrayInto(source, metadata.deserializedType, instance[keyName]); - } - else { - instance[keyName] = deserializeArray(source, null); - } - } - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - var deserializedDate = new Date(source); - if (instance[keyName] instanceof Date) { - instance[keyName].setTime(deserializedDate.getTime()); - } - else { - instance[keyName] = deserializedDate; - } - } - else if (typeof source === "string" && type === RegExp) { - instance[keyName] = new RegExp(source); - } - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObjectInto(source, metadata.deserializedType, instance[keyName]); - } - else { - instance[keyName] = deserializeObjectInto(source, metadata.deserializedType, instance[keyName]); - } - } - else { - instance[keyName] = source; - } - } - //invoke our after deserialized callback if provided - invokeDeserializeHook(instance, json, type); - return instance; -} -//deserializes a bit of json into a `type` -export function Deserialize(json, type) { - if (Array.isArray(json)) { - return deserializeArray(json, type); - } - else if (json && typeof json === "object") { - return deserializeObject(json, type); - } - else if ((typeof json === "string" || json instanceof Date) && type === Date.prototype.constructor) { - return new Date(json); - } - else if (typeof json === "string" && type === RegExp) { - return new RegExp(json); - } - else { - return json; - } -} -//takes some json, a type, and a target object and deserializes the json into that object -export function DeserializeInto(source, type, target) { - if (Array.isArray(source)) { - return deserializeArrayInto(source, type, target || []); - } - else if (source && typeof source === "object") { - return deserializeObjectInto(source, type, target || new type()); - } - else { - return target || (type && new type()) || null; - } -} -//deserializes an array of json into an array of `type` -function deserializeArray(source, type) { - var retn = new Array(source.length); - for (var i = 0; i < source.length; i++) { - retn[i] = Deserialize(source[i], type); - } - return retn; -} -function invokeDeserializeHook(instance, json, type) { - if (type && typeof (type).OnDeserialized === "function") { - type.OnDeserialized(instance, json); - } -} -function invokeSerializeHook(instance, json) { - if (typeof (instance.constructor).OnSerialized === "function") { - (instance.constructor).OnSerialized(instance, json); - } -} -//deserialize a bit of json into an instance of `type` -function deserializeObject(json, type) { - var metadataArray = TypeMap.get(type); - //if we dont have meta data, just decode the json and use that - if (!metadataArray) { - var inst = null; - if (!type) { - inst = JSON.parse(JSON.stringify(json)); - } - else { - inst = new type(); //todo this probably wrong - invokeDeserializeHook(inst, json, type); - } - return inst; - } - var instance = new type(); - //for each tagged property on the source type, try to deserialize it - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - if (!metadata.deserializedKey) - continue; - var serializedKey = metadata.deserializedKey; - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - var source = json[serializedKey]; - var keyName = metadata.keyName; - if (source === void 0) - continue; - if (source === null) { - instance[keyName] = source; - } - else if (metadata.deserializedType && typeof metadata.deserializedType.Deserialize === "function") { - instance[keyName] = metadata.deserializedType.Deserialize(source); - } - else if (Array.isArray(source)) { - instance[keyName] = deserializeArray(source, metadata.deserializedType || null); - } - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - instance[keyName] = new Date(source); - } - else if (typeof source === "string" && metadata.deserializedType === RegExp) { - instance[keyName] = new RegExp(json); - } - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObject(source, metadata.deserializedType); - } - else { - instance[keyName] = deserializeObject(source, metadata.deserializedType); - } - } - else { - instance[keyName] = source; - } - } - invokeDeserializeHook(instance, json, type); - return instance; -} -function deserializeIndexableObject(source, type) { - var retn = {}; - //todo apply key transformation here? - Object.keys(source).forEach(function (key) { - retn[key] = deserializeObject(source[key], type); - }); - return retn; -} -function deserializeIndexableObjectInto(source, type, instance) { - //todo apply key transformation here? - Object.keys(source).forEach(function (key) { - instance[key] = deserializeObjectInto(source[key], type, instance[key]); - }); - return instance; -} -//take an array and spit out json -function serializeArray(source, type) { - var serializedArray = new Array(source.length); - for (var j = 0; j < source.length; j++) { - serializedArray[j] = Serialize(source[j], type); - } - return serializedArray; -} -//take an instance of something and try to spit out json for it based on property annotaitons -function serializeTypedObject(instance, type) { - var json = {}; - var metadataArray; - if (type) { - metadataArray = TypeMap.get(type); - } - else { - metadataArray = TypeMap.get(instance.constructor); - } - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - if (!metadata.serializedKey) - continue; - var serializedKey = metadata.serializedKey; - if (metadata.serializedKey === metadata.keyName) { - if (typeof serializeKeyTransform === "function") { - serializedKey = serializeKeyTransform(metadata.keyName); - } - } - var source = instance[metadata.keyName]; - if (source === void 0) - continue; - if (Array.isArray(source)) { - json[serializedKey] = serializeArray(source, metadata.serializedType || null); - } - else if (metadata.serializedType && typeof metadata.serializedType.Serialize === "function") { - //todo -- serializeIndexableObject probably isn't needed because of how serialize works - json[serializedKey] = metadata.serializedType.Serialize(source); - } - else { - var value = Serialize(source); - if (value !== void 0) { - json[serializedKey] = value; - } - } - } - invokeSerializeHook(instance, json); - return json; -} -//take an instance of something and spit out some json -export function Serialize(instance, type) { - if (instance === null || instance === void 0) - return null; - if (Array.isArray(instance)) { - return serializeArray(instance, type); - } - if (type && TypeMap.has(type)) { - return serializeTypedObject(instance, type); - } - if (instance.constructor && TypeMap.has(instance.constructor)) { - return serializeTypedObject(instance); - } - if (instance instanceof Date) { - return instance.toISOString(); - } - if (instance instanceof RegExp) { - return instance.toString(); - } - if (instance && typeof instance === 'object' || typeof instance === 'function') { - var keys = Object.keys(instance); - var json = {}; - for (var i = 0; i < keys.length; i++) { - //todo this probably needs a key transform - json[keys[i]] = Serialize(instance[keys[i]]); - } - invokeSerializeHook(instance, json); - return json; - } - return instance; -} -export function GenericDeserialize(json, type) { - return Deserialize(json, type); -} -export function GenericDeserializeInto(json, type, instance) { - return DeserializeInto(json, type, instance); -} -//these are used for transforming keys from one format to another -var serializeKeyTransform = null; -var deserializeKeyTransform = null; -//setter for deserializing key transform -export function DeserializeKeysFrom(transform) { - deserializeKeyTransform = transform; -} -//setter for serializing key transform -export function SerializeKeysTo(transform) { - serializeKeyTransform = transform; -} -//this is kinda dumb but typescript doesnt treat enums as a type, but sometimes you still -//want them to be serialized / deserialized, this does the trick but must be called after -//the enum is defined. -export function SerializableEnumeration(e) { - e.Serialize = function (x) { - return e[x]; - }; - e.Deserialize = function (x) { - return e[x]; - }; -} -//expose the type map -export { TypeMap as __TypeMap }; diff --git a/dist/test.d.ts b/dist/test.d.ts deleted file mode 100644 index e69de29..0000000 diff --git a/dist/test.js b/dist/test.js deleted file mode 100644 index e69de29..0000000 diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 30a78a4..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,45 +0,0 @@ -var gulp = require('gulp'); -var jasmine = require('gulp-jasmine'); -var tsc = require('gulp-tsc'); - -gulp.task('build_tests', function () { - gulp.src('./spec/*.ts').pipe(tsc({ - "module": "commonjs", - "noImplicitAny": true, - "preserveConstEnums": true, - "target": "es5", - "declaration": true, - "listFiles": true, - "diagnostics": true, - "noResolve": false, - "suppressImplicitAnyIndexErrors": true, - "noEmitOnError": true, - "version": "1.5.3", - "experimentalDecorators":true, - "emitDecoratorMetadata":true - })).pipe(gulp.dest('./spec')); -}); - -gulp.task('test', ['build_tests'], function () { - gulp.src(['./spec/**/*_spec.js']) - .pipe(jasmine({verbose: false, includeStackTrace: true})); -}); - -gulp.task('build', function () { - gulp.src('./src/**/*.ts').pipe(tsc({ - "module": "commonjs", - "noImplicitAny": true, - "preserveConstEnums": true, - "target": "es5", - "declaration": true, - "listFiles": true, - "diagnostics": true, - "noResolve": false, - "suppressImplicitAnyIndexErrors": true, - "noEmitOnError": true, - "version": "1.7.3", - "emitDecoratorMetadata":true, - "experimentalDecorators":true - - })).pipe(gulp.dest('./dist')); -}); \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 1b470b3..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist/serialize'); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index facdb8c..858063d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1978 +1,4707 @@ { "name": "cerialize", - "version": "0.1.18", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { - "ansi-regex": { - "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", - "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "@babel/code-frame": { + "version": "7.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.38.tgz", + "integrity": "sha512-JNHofQND7Iiuy3f6RXSillN1uBe87DAp+1ktsBfSxfL3xWeGFyJC9jH5zu2zs7eqVGp2qXWvJZFiJIwOYnaCQw==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "@types/jest": { + "version": "22.1.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-22.1.1.tgz", + "integrity": "sha512-JSh6yk+GkeSkucPa3DllFtpDXe0BMxDTFqCxoryzGKvZiusdb97Sb7X5gnMiKdFGkHbTMjSH+HbE9wrBIzrUTA==", "dev": true }, - "ansi-styles": { - "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "dev": true + }, + "acorn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", + "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", + "dev": true + }, + "acorn-globals": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", + "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", + "dev": true, + "requires": { + "acorn": "5.3.0" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", "dev": true }, - "archy": { - "version": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, "arr-diff": { - "version": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz" + "arr-flatten": "1.1.0" } }, "arr-flatten": { - "version": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz", - "integrity": "sha1-5f/lTUXhnzLyFukeuZyM6JK7YEs=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, - "array-differ": { - "version": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", "dev": true }, - "array-find-index": { - "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", "dev": true }, - "array-uniq": { - "version": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", "dev": true }, "array-unique": { - "version": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, "arrify": { - "version": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "async": { - "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "dev": true }, - "balanced-match": { - "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "beeper": { - "version": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz", - "integrity": "sha1-nub8HOf1T+qs585zWIsFYDeGaiw=", + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, - "brace-expansion": { - "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz", - "integrity": "sha1-cZfX6qm4fmSDkOph/GbIRCdCDfk=", + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", "dev": true, "requires": { - "balanced-match": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "concat-map": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "lodash": "4.17.4" } }, - "braces": { - "version": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "preserve": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "repeat-element": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz" - } + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true }, - "buffer-shims": { - "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, - "builtin-modules": { - "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "byline": { - "version": "https://registry.npmjs.org/byline/-/byline-4.2.2.tgz", - "integrity": "sha1-wgOpilsCkIIqk4anjtosvVvNsy8=", + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, - "camelcase": { - "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", "dev": true }, - "camelcase-keys": { - "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "camelcase": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "map-obj": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } } }, - "chalk": { - "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", "dev": true, "requires": { - "ansi-styles": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "escape-string-regexp": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "has-ansi": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "strip-ansi": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" } }, - "clone": { - "version": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", - "dev": true - }, - "clone-stats": { - "version": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } }, - "concat-map": { - "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } }, - "core-util-is": { - "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "babel-jest": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.1.0.tgz", + "integrity": "sha512-5pKRFTlDr+x1JESNRd5leqvxEJk3dRwVvIXikB6Lr4BWZbBppk1Wp+BLUzxWL8tM+EYGLCWgfqkD35Sft8r8Lw==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "4.1.5", + "babel-preset-jest": "22.1.0" + } }, - "currently-unhandled": { - "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "array-find-index": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz" + "babel-runtime": "6.26.0" } }, - "dateformat": { - "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "babel-plugin-istanbul": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz", + "integrity": "sha1-Z2DN2Xf0EdPhdbsGTyvDJ9mbK24=", "dev": true, "requires": { - "get-stdin": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "meow": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz" + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.9.1", + "test-exclude": "4.1.1" } }, - "decamelize": { - "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "babel-plugin-jest-hoist": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.1.0.tgz", + "integrity": "sha512-Og5sjbOZc4XUI3njqwYhS6WLTlHQUJ/y5+dOqmst8eHrozYZgT4OMzAaYaxhk75c2fBVYwn7+mNEN97XDO7cOw==", "dev": true }, - "defaults": { - "version": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", "dev": true, "requires": { - "clone": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz" + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" } }, - "deprecated": { - "version": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true - }, - "detect-file": { - "version": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=", + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "dev": true, "requires": { - "fs-exists-sync": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz" + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" } }, - "duplexer2": { - "version": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "babel-preset-jest": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.1.0.tgz", + "integrity": "sha512-ps2UYz7IQpP2IgZ41tJjUuUDTxJioprHXD8fi9DoycKDGNqB3nAX/ggy1S3plaQd43ktBvMS1FkkyGNoBujFpg==", "dev": true, "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + "babel-plugin-jest-hoist": "22.1.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0" } }, - "duplexify": { - "version": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.5.tgz", - "integrity": "sha1-Dn4oenda91O/V+bnt/IfGD9sOlM=", + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "dev": true, "requires": { - "end-of-stream": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", - "stream-shift": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz" + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.3", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" }, "dependencies": { - "end-of-stream": { - "version": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", - "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=", + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" - } - }, - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz", - "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", - "dev": true, - "requires": { - "buffer-shims": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "source-map": "0.5.7" } } } }, - "end-of-stream": { - "version": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" } }, - "error-ex": { - "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", - "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "is-arrayish": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" } }, - "escape-string-regexp": { - "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "exit": { - "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "is-posix-bracket": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz" + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" } }, - "expand-range": { - "version": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "fill-range": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz" + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" } }, - "expand-tilde": { - "version": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, + "optional": true, "requires": { - "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + "tweetnacl": "0.14.5" } }, - "extend": { - "version": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", - "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=", + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", "dev": true }, - "extglob": { - "version": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { - "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" + "hoek": "4.2.0" } }, - "fancy-log": { - "version": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.2.0.tgz", - "integrity": "sha1-1aUbU+mrIsoH1VjytnrlX9tfy9g=", + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "time-stamp": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.0.1.tgz" + "balanced-match": "1.0.0", + "concat-map": "0.0.1" } }, - "filename-regex": { - "version": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz", - "integrity": "sha1-mW4+gEebmLmJfxWopYs9CE6SZ3U=", - "dev": true - }, - "fill-range": { - "version": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "is-number": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "isobject": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "randomatic": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz", - "repeat-element": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "repeat-string": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" } }, - "find-index": { - "version": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "browser-process-hrtime": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz", + "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=", "dev": true }, - "find-up": { - "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", "dev": true, "requires": { - "path-exists": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "resolve": "1.1.7" } }, - "findup-sync": { - "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz", - "integrity": "sha1-qBF9D3MST1pFRoOVef5S1xKfteU=", + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true, "requires": { - "detect-file": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz", - "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "micromatch": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "resolve-dir": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz" + "node-int64": "0.4.0" } }, - "fined": { - "version": "https://registry.npmjs.org/fined/-/fined-1.0.1.tgz", - "integrity": "sha1-xIr5q1qOD0AKA3XoQVTDdnTav9Q=", + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, + "optional": true, "requires": { - "expand-tilde": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "lodash.assignwith": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "lodash.isarray": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz", - "lodash.isempty": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", - "lodash.isplainobject": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "lodash.isstring": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "lodash.pick": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "parse-filepath": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz" + "align-text": "0.1.4", + "lazy-cache": "1.0.4" }, "dependencies": { - "lodash.isarray": { - "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz", - "integrity": "sha1-KspJayjEym1yZxUxNZDALm6jRAM=", - "dev": true + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true } } }, - "first-chunk-stream": { - "version": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } }, - "flagged-respawn": { - "version": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.2.tgz", - "integrity": "sha1-/xke3c1wiKZ1smEP/8l2vpuAdLU=", - "dev": true + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "fsevents": "1.1.3", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } }, - "for-in": { - "version": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz", - "integrity": "sha1-yfluib+tGKVFr17D7TUqHZ5bTcg=", + "ci-info": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.2.tgz", + "integrity": "sha512-uTGIPNx/nSpBdsF6xnseRXLLtfr9VLqkz8ZqHXr3Y7b6SftyRxBGjwMtJj1OhNbmlc1wZzLNAlAcvyIiE8a6ZA==", "dev": true }, - "for-own": { - "version": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz", - "integrity": "sha1-AUm0GjkIjHUV9R6+HBOG1F+TUHI=", + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, + "optional": true, "requires": { - "for-in": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz" + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } } }, - "fs-exists-sync": { - "version": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "fs.realpath": { - "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "gaze": { - "version": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { - "globule": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz" + "color-name": "1.1.3" } }, - "get-stdin": { - "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "dev": true, "requires": { - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz" + "delayed-stream": "1.0.0" } }, - "glob-base": { - "version": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-type-parser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cpx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz", + "integrity": "sha1-GFvgGFEdhycN7czCkxceN2VauI8=", "dev": true, "requires": { - "glob-parent": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" + "babel-runtime": "6.26.0", + "chokidar": "1.7.0", + "duplexer": "0.1.1", + "glob": "7.1.2", + "glob2base": "0.0.12", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "resolve": "1.1.7", + "safe-buffer": "5.1.1", + "shell-quote": "1.6.1", + "subarg": "1.0.0" } }, - "glob-parent": { - "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" } }, - "glob-stream": { - "version": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "glob2base": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "ordered-read-streams": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "unique-stream": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz" + "boom": "5.2.0" }, "dependencies": { - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - } - }, - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", "dev": true, "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "hoek": "4.2.0" } } } }, - "glob-watcher": { - "version": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "gaze": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz" + "assert-plus": "1.0.0" } }, - "glob2base": { - "version": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "find-index": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz" + "ms": "2.0.0" } }, - "global-modules": { - "version": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "global-prefix": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.4.tgz", - "is-windows": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz" + "strip-bom": "2.0.0" } }, - "global-prefix": { - "version": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.4.tgz", - "integrity": "sha1-BRWNsc3i3UkbRV4pDrOri/xFxuE=", + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "ini": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "is-windows": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "osenv": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", - "which": "https://registry.npmjs.org/which/-/which-1.2.11.tgz" + "foreach": "2.0.5", + "object-keys": "1.0.11" } }, - "globule": { - "version": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz" - }, - "dependencies": { - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz" - } - }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "sigmund": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz" - } - } + "repeating": "2.0.1" } }, - "glogg": { - "version": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", - "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "dev": true, "requires": { - "sparkles": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz" + "webidl-conversions": "4.0.2" } }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha1-uqy6N9GdEfnRRtNXi8mZWMN4fik=", - "dev": true - }, - "gulp": { - "version": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", - "dev": true, - "requires": { - "archy": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "deprecated": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", - "interpret": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz", - "liftoff": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "orchestrator": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.7.tgz", - "pretty-hrtime": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.2.tgz", - "semver": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "tildify": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "v8flags": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.11.tgz", - "vinyl-fs": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz" - } - }, - "gulp-jasmine": { - "version": "https://registry.npmjs.org/gulp-jasmine/-/gulp-jasmine-2.4.2.tgz", - "integrity": "sha1-Wn9H4nNww2GawKKkQr45lnFAnbM=", - "dev": true, - "requires": { - "arrify": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", - "jasmine": "https://registry.npmjs.org/jasmine/-/jasmine-2.5.2.tgz", - "jasmine-terminal-reporter": "https://registry.npmjs.org/jasmine-terminal-reporter/-/jasmine-terminal-reporter-1.0.2.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz" - } - }, - "gulp-tsc": { - "version": "https://registry.npmjs.org/gulp-tsc/-/gulp-tsc-1.2.4.tgz", - "integrity": "sha1-FGaoqCzJoJncYJEtvVovhl0rdLE=", - "dev": true, - "requires": { - "async": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "byline": "https://registry.npmjs.org/byline/-/byline-4.2.2.tgz", - "gulp-util": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", - "lodash": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "node-version-compare": "https://registry.npmjs.org/node-version-compare/-/node-version-compare-1.0.1.tgz", - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "temp": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", - "vinyl-fs": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-1.0.0.tgz", - "which": "https://registry.npmjs.org/which/-/which-1.2.11.tgz" + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz", + "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", + "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", + "dev": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.5.7" }, "dependencies": { - "clone": { - "version": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", "dev": true - }, - "glob-stream": { - "version": "https://registry.npmjs.org/glob-stream/-/glob-stream-4.1.1.tgz", - "integrity": "sha1-uELfENaIx+trz869hG84UilrMgA=", - "dev": true, + } + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "exec-sh": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz", + "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==", + "dev": true, + "requires": { + "merge": "1.2.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "expect": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-22.1.0.tgz", + "integrity": "sha512-8K+8TjNnZq73KYtqNWKWTbYbN8z4loeL+Pn2bqpmtTdBtLNXJtpz9vkUcQlFsgKMDRA3VM8GXRA6qbV/oBF7Bw==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "jest-diff": "22.1.0", + "jest-get-type": "22.1.0", + "jest-matcher-utils": "22.1.0", + "jest-message-util": "22.1.0", + "jest-regex-util": "22.1.0" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "2.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.2", + "minimatch": "3.0.4" + } + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", + "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.8.0", + "node-pre-gyp": "0.6.39" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "optional": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "glob2base": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "ordered-read-streams": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "unique-stream": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz" + "assert-plus": "1.0.0" }, "dependencies": { - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "assert-plus": { + "version": "1.0.0", + "bundled": true, "dev": true, - "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } + "optional": true } } }, - "glob-watcher": { - "version": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.8.tgz", - "integrity": "sha1-aK62Yefizo02NDgbLsQV8AxrwqQ=", + "debug": { + "version": "2.6.8", + "bundled": true, "dev": true, + "optional": true, "requires": { - "gaze": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz" + "ms": "2.0.0" } }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "deep-extend": { + "version": "0.4.2", + "bundled": true, "dev": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true, "requires": { - "natives": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz" + "jsbn": "0.1.1" } }, - "lodash": { - "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true + "extend": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true }, - "object-assign": { - "version": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", + "extsprintf": { + "version": "1.0.2", + "bundled": true, "dev": true }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "forever-agent": { + "version": "0.6.1", + "bundled": true, "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "optional": true, "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" } }, - "strip-bom": { - "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, "dev": true, "requires": { - "first-chunk-stream": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "is-utf8": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" } }, - "unique-stream": { - "version": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", - "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, "dev": true, + "optional": true, "requires": { - "json-stable-stringify": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "through2-filter": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz" + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" } }, - "vinyl": { - "version": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "gauge": { + "version": "2.7.4", + "bundled": true, "dev": true, + "optional": true, "requires": { - "clone": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz" + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" } }, - "vinyl-fs": { - "version": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-1.0.0.tgz", - "integrity": "sha1-0VdS5owtrXQ2Tn6FNHNzU1RpLt8=", + "getpass": { + "version": "0.1.7", + "bundled": true, "dev": true, + "optional": true, "requires": { - "duplexify": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.5.tgz", - "glob-stream": "https://registry.npmjs.org/glob-stream/-/glob-stream-4.1.1.tgz", - "glob-watcher": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.8.tgz", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "merge-stream": "https://registry.npmjs.org/merge-stream/-/merge-stream-0.1.8.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "vinyl": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz" + "assert-plus": "1.0.0" }, "dependencies": { - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "assert-plus": { + "version": "1.0.0", + "bundled": true, "dev": true, - "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } + "optional": true } } - } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true, + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.39", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "1.0.2", + "hawk": "3.1.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "0.1.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.3" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "import-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "2.0.0", + "resolve-cwd": "2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.11.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-ci": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", + "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "dev": true, + "requires": { + "ci-info": "1.1.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", + "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.2.1.tgz", + "integrity": "sha512-oFCwXvd65amgaPCzqrR+a2XjanS1MvpXN6l/MlMUTv6uiA1NOgGX+I0uyq8Lg3GDxsxPsaP1049krz3hIJ5+KA==", + "dev": true, + "requires": { + "async": "2.6.0", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-hook": "1.1.0", + "istanbul-lib-instrument": "1.9.1", + "istanbul-lib-report": "1.1.2", + "istanbul-lib-source-maps": "1.2.2", + "istanbul-reports": "1.1.3", + "js-yaml": "3.10.0", + "mkdirp": "0.5.1", + "once": "1.4.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", + "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz", + "integrity": "sha512-RQmXeQ7sphar7k7O1wTNzVczF9igKpaeGQAG9qR2L+BS4DCJNTI9nytRmIVYevwO0bbq+2CXvJmYDuz0gMrywA==", + "dev": true, + "requires": { + "babel-generator": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.5.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz", + "integrity": "sha512-UTv4VGx+HZivJQwAo1wnRwe1KTvFpfi/NYwN7DcsrdzMXwpRT/Yb6r4SBPoHWj4VuQPakR32g4PUUeyKkdDkBA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz", + "integrity": "sha512-8BfdqSfEdtip7/wo1RnrvLpHVEd8zMZEDmOFEnpC6dg0vXflHt9nvoAyQUzig2uMSXfF2OBEYBV3CVjIL9JvaQ==", + "dev": true, + "requires": { + "debug": "3.1.0", + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.3.tgz", + "integrity": "sha512-ZEelkHh8hrZNI5xDaKwPMFwDsUf5wIEI2bXAFGp1e6deR2mnEKBPhLJEgr4ZBt8Gi6Mj38E/C8kcy9XLggVO2Q==", + "dev": true, + "requires": { + "handlebars": "4.0.11" + } + }, + "jest": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-22.1.4.tgz", + "integrity": "sha512-cIPkn+OFGabazPesbhnYkadPftoO2Fo3w84QjeIP+A8eZ5qj7Zs4PuTemAW8StNMxySJr0KPk/LhYG2GUHLexQ==", + "dev": true, + "requires": { + "jest-cli": "22.1.4" + }, + "dependencies": { + "jest-cli": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-22.1.4.tgz", + "integrity": "sha512-p7yOu0Q5uuXb3Q93qEg3LE6eNGgAGueakifxXNEqQx4b0lOl2YlC9t6BLQWNOJ+z42VWK/BIdFjf6lxKcTkjFA==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "exit": "0.1.2", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "import-local": "1.0.0", + "is-ci": "1.1.0", + "istanbul-api": "1.2.1", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-instrument": "1.9.1", + "istanbul-lib-source-maps": "1.2.2", + "jest-changed-files": "22.1.4", + "jest-config": "22.1.4", + "jest-environment-jsdom": "22.1.4", + "jest-get-type": "22.1.0", + "jest-haste-map": "22.1.0", + "jest-message-util": "22.1.0", + "jest-regex-util": "22.1.0", + "jest-resolve-dependencies": "22.1.0", + "jest-runner": "22.1.4", + "jest-runtime": "22.1.4", + "jest-snapshot": "22.1.2", + "jest-util": "22.1.4", + "jest-worker": "22.1.0", + "micromatch": "2.3.11", + "node-notifier": "5.2.1", + "realpath-native": "1.0.0", + "rimraf": "2.6.2", + "slash": "1.0.0", + "string-length": "2.0.0", + "strip-ansi": "4.0.0", + "which": "1.3.0", + "yargs": "10.1.2" + } + } + } + }, + "jest-changed-files": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.1.4.tgz", + "integrity": "sha512-EpqJhwt+N/wEHRT+5KrjagVrunduOfMgAb7fjjHkXHFCPRZoVZwl896S7krx7txf5hrMNUkpECnOnO2wBgzJCw==", + "dev": true, + "requires": { + "throat": "4.1.0" + } + }, + "jest-config": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-22.1.4.tgz", + "integrity": "sha512-ZImFp7STrUDOgQLW5I5UloCiCRMh6HmMIYIoWqaQkxnR5ws7MuZFG/Ns9sZFyfrnyWCvcW91e+XcEfNeoa4Jew==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "glob": "7.1.2", + "jest-environment-jsdom": "22.1.4", + "jest-environment-node": "22.1.4", + "jest-get-type": "22.1.0", + "jest-jasmine2": "22.1.4", + "jest-regex-util": "22.1.0", + "jest-resolve": "22.1.4", + "jest-util": "22.1.4", + "jest-validate": "22.1.2", + "pretty-format": "22.1.0" + } + }, + "jest-diff": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.1.0.tgz", + "integrity": "sha512-lowdbU/dzXh+2/MR5QcvU5KPNkO4JdAEYw0PkQCbIQIuy5+g3QZBuVhWh8179Fmpg4CQrz1WgoK/yQHDCHbqqw==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "diff": "3.4.0", + "jest-get-type": "22.1.0", + "pretty-format": "22.1.0" + } + }, + "jest-docblock": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-22.1.0.tgz", + "integrity": "sha512-/+OGgBVRJb5wCbXrB1LQvibQBz2SdrvDdKRNzY1gL+OISQJZCR9MOewbygdT5rVzbbkfhC4AR2x+qWmNUdJfjw==", + "dev": true, + "requires": { + "detect-newline": "2.1.0" + } + }, + "jest-environment-jsdom": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.1.4.tgz", + "integrity": "sha512-YGqFJzei/kq5BgQ8su7igLoCl34ytUffr5ZoqwLrDzCmXUKyIiuwBFbWe3xFMG/crlDb1emhBXdzWM1yDEDw5Q==", + "dev": true, + "requires": { + "jest-mock": "22.1.0", + "jest-util": "22.1.4", + "jsdom": "11.6.2" + } + }, + "jest-environment-node": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-22.1.4.tgz", + "integrity": "sha512-rQmtzgZVdyCzeXsE8i7Alw2483KSd2PYjssZWZYeNzonN/lBeUjjaOCgLWp6FspBzSTnYF7x6cN4umGZxYAhow==", + "dev": true, + "requires": { + "jest-mock": "22.1.0", + "jest-util": "22.1.4" + } + }, + "jest-get-type": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.1.0.tgz", + "integrity": "sha512-nD97IVOlNP6fjIN5i7j5XRH+hFsHL7VlauBbzRvueaaUe70uohrkz7pL/N8lx/IAwZRTJ//wOdVgh85OgM7g3w==", + "dev": true + }, + "jest-haste-map": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-22.1.0.tgz", + "integrity": "sha512-vETdC6GboGlZX6+9SMZkXtYRQSKBbQ47sFF7NGglbMN4eyIZBODply8rlcO01KwBiAeiNCKdjUyfonZzJ93JEg==", + "dev": true, + "requires": { + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.11", + "jest-docblock": "22.1.0", + "jest-worker": "22.1.0", + "micromatch": "2.3.11", + "sane": "2.3.0" + } + }, + "jest-jasmine2": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-22.1.4.tgz", + "integrity": "sha512-+KoRiG4PUwURB7UXei2jzxvbCebhXgTYS+xWl3FsSYUn3flcxdcOgAsFolx31Dkk/B1bVf1HIKt/B6Ubucp9aQ==", + "dev": true, + "requires": { + "callsites": "2.0.0", + "chalk": "2.3.0", + "co": "4.6.0", + "expect": "22.1.0", + "graceful-fs": "4.1.11", + "is-generator-fn": "1.0.0", + "jest-diff": "22.1.0", + "jest-matcher-utils": "22.1.0", + "jest-message-util": "22.1.0", + "jest-snapshot": "22.1.2", + "source-map-support": "0.5.3" + } + }, + "jest-leak-detector": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-22.1.0.tgz", + "integrity": "sha512-8QsCWkncWAqdvrXN4yXQp9vgWF6CT3RkRey+d06SIHX913uXzAJhJdZyo6eE+uHVYMxUbxqW93npbUFhAR0YxA==", + "dev": true, + "requires": { + "pretty-format": "22.1.0" + } + }, + "jest-matcher-utils": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.1.0.tgz", + "integrity": "sha512-Zn1OD9wVjILOdvRxgAnqiCN36OX6KJx+P2FHN+3lzQ0omG2N2OAguxE1QXuJJneG2yndlkXjekXFP254c0cSpw==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "jest-get-type": "22.1.0", + "pretty-format": "22.1.0" + } + }, + "jest-message-util": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.1.0.tgz", + "integrity": "sha512-kftcoawOeOVUGuGWmMupJt7FGLK1pqOrh02FlJwtImmPGZ2yTWCTx2D+N/g95qD2jCbQ/ntH1goBixhAIIxL+g==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.38", + "chalk": "2.3.0", + "micromatch": "2.3.11", + "slash": "1.0.0", + "stack-utils": "1.0.1" + } + }, + "jest-mock": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-22.1.0.tgz", + "integrity": "sha512-gL3/C8ds6e1PWiOTsV7sIejPP/ECYQgDbwMzbNCc+ZFPuPH3EpwsVLGmQqPK6okgnDagimbbQnss3kPJ8HCMtA==", + "dev": true + }, + "jest-regex-util": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.1.0.tgz", + "integrity": "sha512-on0LqVS6Xeh69sw3d1RukVnur+lVOl3zkmb0Q54FHj9wHoq6dbtWqb3TSlnVUyx36hqjJhjgs/QLqs07Bzu72Q==", + "dev": true + }, + "jest-resolve": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-22.1.4.tgz", + "integrity": "sha512-/HuCMeiTD6YJ+NF15bU1mal1r7Gov0GJozA7232XiYve7cOOnU2JwXBx3EQmcIuG38uNrRPjtgpiXkBqfnk4Og==", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "chalk": "2.3.0" + } + }, + "jest-resolve-dependencies": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-22.1.0.tgz", + "integrity": "sha512-76Ll61bD/Sus8wK8d+lw891EtiBJGJkWG8OuVDTEX0z3z2+jPujvQqSB2eQ+kCHyCsRwJ2PSjhn3UHqae/oEtA==", + "dev": true, + "requires": { + "jest-regex-util": "22.1.0" + } + }, + "jest-runner": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-22.1.4.tgz", + "integrity": "sha512-HAyZ0Q2Fyk7mlbtbSKP75hNs9IP0Md7kzPUN1uNKbvQfZkXA/e7P0ttzAIGQtEbRx656tYwkfWNW+hXvs1i4/g==", + "dev": true, + "requires": { + "exit": "0.1.2", + "jest-config": "22.1.4", + "jest-docblock": "22.1.0", + "jest-haste-map": "22.1.0", + "jest-jasmine2": "22.1.4", + "jest-leak-detector": "22.1.0", + "jest-message-util": "22.1.0", + "jest-runtime": "22.1.4", + "jest-util": "22.1.4", + "jest-worker": "22.1.0", + "throat": "4.1.0" + } + }, + "jest-runtime": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-22.1.4.tgz", + "integrity": "sha512-r/UjVuQppDRwbUprDlLYdd8MTYY+H8H6BCqRujGjo5/QyIt3b0hppNoOQHF+0bHNtuz/sR9chJ9HJ3A1fiv9Pw==", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-jest": "22.1.0", + "babel-plugin-istanbul": "4.1.5", + "chalk": "2.3.0", + "convert-source-map": "1.5.1", + "exit": "0.1.2", + "graceful-fs": "4.1.11", + "jest-config": "22.1.4", + "jest-haste-map": "22.1.0", + "jest-regex-util": "22.1.0", + "jest-resolve": "22.1.4", + "jest-util": "22.1.4", + "json-stable-stringify": "1.0.1", + "micromatch": "2.3.11", + "realpath-native": "1.0.0", + "slash": "1.0.0", + "strip-bom": "3.0.0", + "write-file-atomic": "2.3.0", + "yargs": "10.1.2" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "jest-snapshot": { + "version": "22.1.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-22.1.2.tgz", + "integrity": "sha512-45co/M0gTe6Y6yHaJLydEZKHOFpFHESLah40jW35DWd3pd7q188bsi0oUY4Kls7PDXUamvTWuTKTZXCtzwSvCw==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "jest-diff": "22.1.0", + "jest-matcher-utils": "22.1.0", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "pretty-format": "22.1.0" + } + }, + "jest-util": { + "version": "22.1.4", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-22.1.4.tgz", + "integrity": "sha512-zM29idoVBPvmpsGubS7YmywVyPe4/m1wE2YhmKp0vVmrQmuby7ObuMqabp82EYlM0Rdp4GNEtaDamW9jg8lgTg==", + "dev": true, + "requires": { + "callsites": "2.0.0", + "chalk": "2.3.0", + "graceful-fs": "4.1.11", + "is-ci": "1.1.0", + "jest-message-util": "22.1.0", + "jest-validate": "22.1.2", + "mkdirp": "0.5.1" + } + }, + "jest-validate": { + "version": "22.1.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-22.1.2.tgz", + "integrity": "sha512-IjvMsV7GW5ghg5PTQvU23zJqTBmnq10eY+4n47awUeXYEGH27N+JajFPOg6tsN+OYvEPsohPquKoqQ5XBVs/ow==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "jest-get-type": "22.1.0", + "leven": "2.1.0", + "pretty-format": "22.1.0" + } + }, + "jest-worker": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-22.1.0.tgz", + "integrity": "sha512-ezLueYAQowk5N6g2J7bNZfq4NWZvMNB5Qd24EmOZLcM5SXTdiFvxykZIoNiMj9C98cCbPaojX8tfR7b1LJwNig==", + "dev": true, + "requires": { + "merge-stream": "1.0.1" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsdom": { + "version": "11.6.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.6.2.tgz", + "integrity": "sha512-pAeZhpbSlUp5yQcS6cBQJwkbzmv4tWFaYxHbFVSxzXefqjvtRA851Z5N2P+TguVG9YeUDcgb8pdeVQRJh0XR3Q==", + "dev": true, + "requires": { + "abab": "1.0.4", + "acorn": "5.3.0", + "acorn-globals": "4.1.0", + "array-equal": "1.0.0", + "browser-process-hrtime": "0.1.2", + "content-type-parser": "1.0.2", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "domexception": "1.0.1", + "escodegen": "1.9.0", + "html-encoding-sniffer": "1.0.2", + "left-pad": "1.2.0", + "nwmatcher": "1.4.3", + "parse5": "4.0.0", + "pn": "1.1.0", + "request": "2.83.0", + "request-promise-native": "1.0.5", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.3", + "w3c-hr-time": "1.0.1", + "webidl-conversions": "4.0.2", + "whatwg-encoding": "1.0.3", + "whatwg-url": "6.4.0", + "ws": "4.0.0", + "xml-name-validator": "3.0.0" + } + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" } }, - "gulp-util": { - "version": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz", - "integrity": "sha1-eJJcS4+LSQBawBoBHFV+YhiUHLs=", + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "array-differ": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "array-uniq": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "beeper": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz", - "chalk": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "dateformat": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "fancy-log": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.2.0.tgz", - "gulplog": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "has-gulplog": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "lodash._reescape": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "lodash._reevaluate": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "lodash.template": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "multipipe": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "replace-ext": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", - "vinyl": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz" + "graceful-fs": "4.1.11" } }, - "gulplog": { - "version": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { - "glogg": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" } }, - "has-ansi": { - "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "is-buffer": "1.1.6" } }, - "has-gulplog": { - "version": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "sparkles": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz" + "invert-kv": "1.0.0" } }, - "hosted-git-info": { - "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", - "integrity": "sha1-C6gdkNouJas0ozLm7HeTbhWYEYs=", + "left-pad": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz", + "integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4=", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", "dev": true }, - "indent-string": { - "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "repeating": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, - "inflight": { - "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", - "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, - "inherits": { - "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, - "ini": { - "version": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "interpret": { - "version": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz", - "integrity": "sha1-1Xn7f2k7hYAElHrzn6DbSfeVYCw=", + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, - "is-absolute": { - "version": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.5.tgz", - "integrity": "sha1-mUFCufRo0nwU+/DNMP5325NMp20=", + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "is-relative": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", - "is-windows": "https://registry.npmjs.org/is-windows/-/is-windows-0.1.1.tgz" - }, - "dependencies": { - "is-windows": { - "version": "https://registry.npmjs.org/is-windows/-/is-windows-0.1.1.tgz", - "integrity": "sha1-vjEHFUMc+rzMVKs5USEPoLbQGr4=", - "dev": true - } + "js-tokens": "3.0.2" } }, - "is-arrayish": { - "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz", - "integrity": "sha1-z8hszV3FpS+oBIkRHGkgxFfi2Ys=", - "dev": true - }, - "is-builtin-module": { - "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { - "builtin-modules": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, - "is-dotfile": { - "version": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz", - "integrity": "sha1-LBMjg/ORmfjtwmjKAbmwB9IFzE0=", - "dev": true - }, - "is-equal-shallow": { - "version": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", "dev": true, "requires": { - "is-primitive": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" + "tmpl": "1.0.4" } }, - "is-extendable": { - "version": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } }, - "is-extglob": { - "version": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", "dev": true }, - "is-finite": { - "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", "dev": true, "requires": { - "number-is-nan": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + "readable-stream": "2.3.3" } }, - "is-glob": { - "version": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" } }, - "is-number": { - "version": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", "dev": true, "requires": { - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz" + "mime-db": "1.30.0" } }, - "is-posix-bracket": { - "version": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, - "is-relative": { - "version": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz", - "integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=", + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "is-unc-path": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.1.tgz" + "brace-expansion": "1.1.8" } }, - "is-unc-path": { - "version": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.1.tgz", - "integrity": "sha1-qyUz13rXM1YRJMPcD1zYuQBUyGs=", + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { - "unc-path-regex": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz" + "minimist": "0.0.8" } }, - "is-utf8": { - "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "is-windows": { - "version": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", - "dev": true + "nan": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "dev": true, + "optional": true }, - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "isexe": { - "version": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", - "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=", + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "isobject": { - "version": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "node-notifier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", + "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", "dev": true, "requires": { - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - }, - "dependencies": { - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } + "growly": "1.3.0", + "semver": "5.5.0", + "shellwords": "0.1.1", + "which": "1.3.0" } }, - "jasmine": { - "version": "https://registry.npmjs.org/jasmine/-/jasmine-2.5.2.tgz", - "integrity": "sha1-YoPO9whcCVzCXWUelU3wBPfj5CE=", + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "exit": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz", - "jasmine-core": "2.5.2" - }, - "dependencies": { - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz", - "integrity": "sha1-Nq3YVtdG0NmeTMJ5e7oa4sZycv0=", - "dev": true, - "requires": { - "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - } - }, - "jasmine-core": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.5.2.tgz", - "integrity": "sha1-b2G9eQYeJ/Q+b5NV5Es8bKtv8pc=", - "dev": true - }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", - "dev": true, - "requires": { - "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" - } - } + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.1" } }, - "jasmine-core": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.6.2.tgz", - "integrity": "sha1-dOoffPQoaRryARB9YxI0AnoJ2qs=", - "dev": true - }, - "jasmine-terminal-reporter": { - "version": "https://registry.npmjs.org/jasmine-terminal-reporter/-/jasmine-terminal-reporter-1.0.2.tgz", - "integrity": "sha1-049Jar5DoI7dwNGM3fFM0RjZ5E4=", + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "indent-string": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "pluralize": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz" + "remove-trailing-separator": "1.1.0" } }, - "json-stable-stringify": { - "version": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "jsonify": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" + "path-key": "2.0.1" } }, - "jsonify": { - "version": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "kind-of": { - "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz", - "integrity": "sha1-e47PGKThf4Jp1ztQHJ8jLJaIenQ=", + "nwmatcher": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.3.tgz", + "integrity": "sha512-IKdSTiDWCarf2JTS5e9e2+5tPZGdkRJ79XjYV0pzK8Q9BpsFyBq1RGKxzs7Q8UBushGw7m6TzVKz6fcY99iSWw==", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { - "is-buffer": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz" + "define-properties": "1.1.2", + "es-abstract": "1.10.0" } }, - "liftoff": { - "version": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz", - "integrity": "sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=", + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "extend": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", - "findup-sync": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.2.tgz", - "fined": "https://registry.npmjs.org/fined/-/fined-1.0.1.tgz", - "flagged-respawn": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.2.tgz", - "lodash.isplainobject": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "lodash.isstring": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "lodash.mapvalues": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", - "rechoir": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + "for-own": "0.1.5", + "is-extendable": "0.1.1" } }, - "load-json-file": { - "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.9.tgz", - "parse-json": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" + "wrappy": "1.0.2" } }, - "lodash": { - "version": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lodash._basecopy": { - "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } }, - "lodash._basetostring": { - "version": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } }, - "lodash._basevalues": { - "version": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, - "lodash._getnative": { - "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } }, - "lodash._isiterateecall": { - "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "lodash._reescape": { - "version": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "lodash._reevaluate": { - "version": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true + "p-limit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } }, - "lodash._reinterpolate": { - "version": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.2.0" + } }, - "lodash._root": { - "version": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, - "lodash.assignwith": { - "version": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "integrity": "sha1-EnqX8CrcQXUalU0ksN4X4QDgOOs=", - "dev": true + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } }, - "lodash.escape": { - "version": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "lodash._root": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz" + "error-ex": "1.3.1" } }, - "lodash.isarguments": { - "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "dev": true }, - "lodash.isarray": { - "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, - "lodash.isempty": { - "version": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", - "integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=", + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "lodash.isplainobject": { - "version": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, - "lodash.isstring": { - "version": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, - "lodash.keys": { - "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "lodash._getnative": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "lodash.isarguments": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "lodash.isarray": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, - "lodash.mapvalues": { - "version": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", - "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "lodash.pick": { - "version": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, - "lodash.restparam": { - "version": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, - "lodash.template": { - "version": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "lodash._basetostring": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "lodash._basevalues": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "lodash._isiterateecall": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "lodash.escape": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "lodash.keys": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "lodash.restparam": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "lodash.templatesettings": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz" - } - }, - "lodash.templatesettings": { - "version": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "lodash._reinterpolate": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "lodash.escape": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz" + "pinkie": "2.0.4" } }, - "loud-rejection": { - "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "currently-unhandled": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "signal-exit": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.1.tgz" + "find-up": "2.1.0" } }, - "lru-cache": { - "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, - "map-cache": { - "version": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, - "map-obj": { - "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, - "meow": { - "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "pretty-format": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.1.0.tgz", + "integrity": "sha512-0HHR5hCmjDGU4sez3w5zRDAAwn7V0vT4SgPiYPZ1XDm5sT3Icb+Bh+fsOP3+Y3UwPjMr7TbRj+L7eQyMkPAxAw==", "dev": true, "requires": { - "camelcase-keys": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "decamelize": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "loud-rejection": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "map-obj": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "normalize-package-data": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "object-assign": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "read-pkg-up": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "redent": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "trim-newlines": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz" + "ansi-regex": "3.0.0", + "ansi-styles": "3.2.0" }, "dependencies": { - "object-assign": { - "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true } } }, - "merge-stream": { - "version": "https://registry.npmjs.org/merge-stream/-/merge-stream-0.1.8.tgz", - "integrity": "sha1-SKB7O0oSHXSj7b/c20sIrb8CQLE=", + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { - "through2": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } } }, - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "is-buffer": "1.1.6" } } } }, - "micromatch": { - "version": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "arr-diff": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "array-unique": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "braces": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "expand-brackets": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "extglob": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "filename-regex": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz", - "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz", - "normalize-path": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz", - "object.omit": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz", - "parse-glob": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "regex-cache": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz" + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" } }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + } } }, - "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mkdirp": { - "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "dev": true, "requires": { - "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - }, - "dependencies": { - "minimist": { - "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" } }, - "multipipe": { - "version": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, "requires": { - "duplexer2": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz" + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" } }, - "natives": { - "version": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", - "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=", - "dev": true + "realpath-native": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.0.tgz", + "integrity": "sha512-XJtlRJ9jf0E1H1SLeJyQ9PGzQD7S65h1pRXEcAeK48doKOnKxcgPeNohJvD5u/2sI9J1oke6E8bZHS/fmW1UiQ==", + "dev": true, + "requires": { + "util.promisify": "1.0.0" + } }, - "node-version-compare": { - "version": "https://registry.npmjs.org/node-version-compare/-/node-version-compare-1.0.1.tgz", - "integrity": "sha1-2Fv9IPCsreM1d/VmgscQnDTFUM0=", + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, - "normalize-package-data": { - "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "hosted-git-info": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", - "is-builtin-module": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "semver": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "validate-npm-package-license": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz" + "is-equal-shallow": "0.1.3" } }, - "normalize-path": { - "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz", - "integrity": "sha1-R4hqwWYnYNQmG32XnSQXCdPOP3o=", + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, - "number-is-nan": { - "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "dev": true }, - "object-assign": { - "version": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, - "object.omit": { - "version": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz", - "integrity": "sha1-hoWXMz1U5gZilAu0WGBd1q4S/pQ=", + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "dev": true, "requires": { - "for-own": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz", - "is-extendable": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" } }, - "once": { - "version": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "dev": true, "requires": { - "wrappy": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "lodash": "4.17.4" } }, - "orchestrator": { - "version": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.7.tgz", - "integrity": "sha1-xFBk4ixaKnuZc09AmpX/7cfTw98=", + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", "dev": true, "requires": { - "end-of-stream": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "sequencify": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "stream-consume": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz" + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" } }, - "ordered-read-streams": { - "version": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "os-homedir": { - "version": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "os-tmpdir": { - "version": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, - "osenv": { - "version": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", - "integrity": "sha1-g88FxtZFj8TVrGNi6jJdkvJ1Qhc=", + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { - "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "os-tmpdir": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + "resolve-from": "3.0.0" } }, - "parse-filepath": { - "version": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz", - "integrity": "sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=", + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, + "optional": true, "requires": { - "is-absolute": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.5.tgz", - "map-cache": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "path-root": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz" + "align-text": "0.1.4" } }, - "parse-glob": { - "version": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob-base": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "is-dotfile": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz", - "is-extglob": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "is-glob": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" + "glob": "7.1.2" } }, - "parse-json": { - "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sane": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-2.3.0.tgz", + "integrity": "sha512-6GB9zPCsqJqQPAGcvEkUPijM1ZUFI+A/DrscL++dXO3Ltt5q5mPDayGxZtr3cBRkrbb4akbwszVVkTIFefEkcg==", "dev": true, "requires": { - "error-ex": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz" + "anymatch": "1.3.2", + "exec-sh": "0.2.1", + "fb-watchman": "2.0.0", + "fsevents": "1.1.3", + "minimatch": "3.0.4", + "minimist": "1.2.0", + "walker": "1.0.7", + "watch": "0.18.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, - "path-exists": { - "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "shebang-regex": "1.0.0" } }, - "path-is-absolute": { - "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "path-root": { - "version": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", "dev": true, "requires": { - "path-root-regex": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz" + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "jsonify": "0.0.0" } }, - "path-root-regex": { - "version": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, - "path-type": { - "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "dev": true, "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.9.tgz", - "pify": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "pinkie-promise": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + "hoek": "4.2.0" } }, - "pify": { - "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, - "pinkie": { - "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "source-map-support": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz", + "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==", + "dev": true, + "requires": { + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } }, - "pinkie-promise": { - "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, "requires": { - "pinkie": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + "spdx-license-ids": "1.2.2" } }, - "pluralize": { - "version": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", "dev": true }, - "preserve": { - "version": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", "dev": true }, - "pretty-hrtime": { - "version": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.2.tgz", - "integrity": "sha1-cMqW9NBiikQ7kYdY95QWqae8n6g=", + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "process-nextick-args": { - "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", "dev": true }, - "randomatic": { - "version": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz", - "integrity": "sha1-Xp718tVzxnvSuBJK6QtRVuRXhAs=", + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", "dev": true, "requires": { - "is-number": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "kind-of": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz" + "astral-regex": "1.0.0", + "strip-ansi": "4.0.0" } }, - "read-pkg": { - "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "load-json-file": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "normalize-package-data": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", - "path-type": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, - "read-pkg-up": { - "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { - "find-up": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "read-pkg": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz" + "safe-buffer": "5.1.1" } }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } } }, - "rechoir": { - "version": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "resolve": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + "is-utf8": "0.2.1" } }, - "redent": { - "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "dev": true, "requires": { - "indent-string": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "strip-indent": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, - "regex-cache": { - "version": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", - "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "is-equal-shallow": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "is-primitive": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" + "has-flag": "2.0.0" } }, - "repeat-element": { - "version": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", - "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "dev": true }, - "repeating": { - "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "test-exclude": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", "dev": true, "requires": { - "is-finite": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz" + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" } }, - "replace-ext": { - "version": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", "dev": true }, - "resolve": { - "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, - "resolve-dir": { - "version": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", "dev": true, "requires": { - "expand-tilde": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "global-modules": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz" + "punycode": "1.4.1" } }, - "rimraf": { - "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", - "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", "dev": true, "requires": { - "glob": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz" + "punycode": "2.1.0" }, "dependencies": { - "glob": { - "version": "https://registry.npmjs.org/glob/-/glob-7.1.0.tgz", - "integrity": "sha1-Nq3YVtdG0NmeTMJ5e7oa4sZycv0=", + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-jest": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-22.0.3.tgz", + "integrity": "sha512-6XSJpBUQwXOBgPnpKIZylx2Q4MOvSpngOj+iTevr0N4RpUT1iWBhdpMJkyjciQexlVkuMJNNOL1iZYBpLBkL4g==", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-plugin-istanbul": "4.1.5", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-preset-jest": "22.1.0", + "cpx": "1.5.0", + "fs-extra": "4.0.3", + "jest-config": "22.1.4", + "pkg-dir": "2.0.0", + "source-map-support": "0.5.3", + "yargs": "11.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", "dev": true, "requires": { - "fs.realpath": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "inflight": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "minimatch": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "once": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "path-is-absolute": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" } }, - "minimatch": { - "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "yargs": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { - "brace-expansion": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz" + "camelcase": "4.1.0" } } } }, - "semver": { - "version": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" }, - "sequencify": { - "version": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", - "dev": true + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } }, - "sigmund": { - "version": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true }, - "signal-exit": { - "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.1.tgz", - "integrity": "sha1-WkyISZK2OnrNm623iUw+6c/MrYE=", - "dev": true + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } }, - "sparkles": { - "version": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", - "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", + "typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz", + "integrity": "sha512-bqB1yS6o9TNA9ZC/MJxM0FZzPnZdtHj0xWK/IZ5khzVqdpGul/R/EIiHRgFXlwTD7PSIaYVnGKq1QgMCu2mnqw==", "dev": true }, - "spdx-correct": { - "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, + "optional": true, "requires": { - "spdx-license-ids": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz" + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } } }, - "spdx-expression-parse": { - "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.3.tgz", - "integrity": "sha1-yjw4KMT+qKpEmXiEs5j8XWdDZEI=", - "dev": true + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true }, - "spdx-license-ids": { - "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, - "stream-consume": { - "version": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", - "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", "dev": true }, - "stream-shift": { - "version": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "string_decoder": { - "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "object.getownpropertydescriptors": "2.0.3" + } + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", "dev": true }, - "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { - "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" } }, - "strip-bom": { - "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "is-utf8": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" } }, - "strip-indent": { - "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", "dev": true, "requires": { - "get-stdin": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + "browser-process-hrtime": "0.1.2" } }, - "supports-color": { - "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "temp": { - "version": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", "dev": true, "requires": { - "os-tmpdir": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "rimraf": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" - }, - "dependencies": { - "rimraf": { - "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "dev": true - } + "makeerror": "1.0.11" } }, - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", - "integrity": "sha1-OE51MU1J8y3hLuu4E2uOtrXVnak=", + "watch": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", + "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", "dev": true, "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "exec-sh": "0.2.1", + "minimist": "1.2.0" }, "dependencies": { - "isarray": { - "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "process-nextick-args": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "util-deprecate": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - } } } }, - "through2-filter": { - "version": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", - "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", - "dev": true, - "requires": { - "through2": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true }, - "tildify": { - "version": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "whatwg-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", + "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", "dev": true, "requires": { - "os-homedir": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + "iconv-lite": "0.4.19" } }, - "time-stamp": { - "version": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.0.1.tgz", - "integrity": "sha1-n0vSNVnJNllm8zAtu6KwfGuZsVE=", - "dev": true - }, - "trim-newlines": { - "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "typescript": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.0.tgz", - "integrity": "sha1-YJiedMrZPCj+Nff3tB/psgWiVwE=" - }, - "unc-path-regex": { - "version": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true - }, - "unique-stream": { - "version": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true - }, - "user-home": { - "version": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - }, - "util-deprecate": { - "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "v8flags": { - "version": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.11.tgz", - "integrity": "sha1-vKjzDw1tYGEswsAGQeaWLUKuaIE=", + "whatwg-url": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", + "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", "dev": true, "requires": { - "user-home": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" } }, - "validate-npm-package-license": { - "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "spdx-correct": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "spdx-expression-parse": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.3.tgz" + "isexe": "2.0.0" } }, - "vinyl": { - "version": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, - "requires": { - "clone": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "replace-ext": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz" - } + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true }, - "vinyl-fs": { - "version": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "defaults": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "glob-stream": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "glob-watcher": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "strip-bom": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "through2": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "vinyl": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" }, "dependencies": { - "clone": { - "version": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "graceful-fs": { - "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", - "dev": true, - "requires": { - "natives": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz" - } - }, - "readable-stream": { - "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "string_decoder": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - } - }, - "strip-bom": { - "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "first-chunk-stream": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "is-utf8": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" + "number-is-nan": "1.0.1" } }, - "through2": { - "version": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "readable-stream": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "xtend": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, - "vinyl": { - "version": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "clone": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "clone-stats": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz" + "ansi-regex": "2.1.1" } } } }, - "which": { - "version": "https://registry.npmjs.org/which/-/which-1.2.11.tgz", - "integrity": "sha1-yLLu6muMFln6fB3U/aq+lTPcXos=", + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", "dev": true, "requires": { - "isexe": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" } }, - "wrappy": { - "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "ws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", + "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, - "xtend": { - "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", + "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "8.1.0" + }, + "dependencies": { + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } } } } diff --git a/package.json b/package.json index ef918df..d2ce839 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cerialize", - "description": "Easy serialization throught ES7/Typescript annotations", + "description": "Easy serialization through ES7/Typescript annotations", "keywords": [ "serialize", "typescript", @@ -12,16 +12,34 @@ "author": "Matt Weichselbaum", "license": "MIT", "repository": "https://github.com/weichx/cerialize", - "version": "0.1.18", - "main": "index.js", - "typings": "dist/serialize.d.ts", + "version": "2.0.0", + "main": "dist/index.js", + "scripts": { + "install": "tsc", + "build": "tsc", + "test": "jest", + "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand" + }, + "typings": "dist/index.d.ts", "devDependencies": { - "gulp": "^3.9.0", - "gulp-jasmine": "^2.0.1", - "gulp-tsc": "^1.1.0", - "jasmine-core": "^2.6.2" + "@types/jest": "^22.1.1", + "jest": "^22.1.4", + "ts-jest": "^22.0.3", + "typescript": "^2.7.1" + }, + "jest": { + "testRegex": "/spec/.*\\.spec\\.([tj]sx?)$", + "transform": { + "^.+\\.[jt]sx?$": "ts-jest" + }, + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx" + ] }, "dependencies": { - "typescript": "^2.5.0" + "tslib": "^1.9.0" } } diff --git a/spec/autoserialize_annotation_spec.ts b/spec/autoserialize_annotation_spec.ts deleted file mode 100644 index f511a79..0000000 --- a/spec/autoserialize_annotation_spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -/// -import {__TypeMap, autoserialize, Serialize, Deserialize, DeserializeInto, autoserializeAs} from '../src/serialize'; - -class T { - @autoserialize public x: number; -} - -class Vector2 { - @autoserialize x: number; - @autoserialize y: number; -} -class AsTest { - @autoserializeAs(Vector2) v: Vector2; -} - -class AsTest2 { - @autoserializeAs(Vector2, "VECTOR") v: Vector2; -} - -class AsTest3 { - @autoserializeAs("z") y: number; -} - -class Test3 { - @autoserialize public primitiveArray: Array; -} - -describe('autoserialize', function () { - it('should create meta data for serialize and deserialize', function () { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - }); -}); - -describe('autoserializeAs', function () { - it('should create meta data', function () { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].serializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].serializedType).toBe(Vector2); - expect(__TypeMap.get(AsTest)[0].deserializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].deserializedType).toBe(Vector2); - }); - - it('should create meta data with a different key', function () { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].serializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].serializedType).toBe(null); - expect(__TypeMap.get(AsTest3)[0].deserializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].deserializedType).toBe(null); - }); - - it('should create meta data with a different key and type', function () { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].serializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].serializedType).toBe(Vector2); - expect(__TypeMap.get(AsTest2)[0].deserializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].deserializedType).toBe(Vector2); - }); - - it("handles strings", function() { - - }) -}); -/* [Weichx 12/9/15] credit to @garkin for contributing the rest of this file */ -// ES6 Set stub -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set -// https://github.com/cloud9ide/typescript/blob/master/typings/lib.d.ts -interface Set { - add(value: T): Set; - clear(): void; - delete(value: T): boolean; - forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void; - has(value: T): boolean; - size: number; -} -declare var Set: { - new (data?: T[]): Set; -}; - -module Utility { - export function unpackSet(_set: Set): T[] { - const result: T[] = []; - _set.forEach(v => result.push(v)); - return result; - } -} - -describe('autoserializeAs using Serializer', () => { - - describe('to wrapped data', () => { - - const JSON = { - children: { - wrap: [11, 22, 33] - } - }; - - const Serializer = { - Serialize(_set: Set){ - return {wrap: Utility.unpackSet(_set)}; - }, - Deserialize(json: any, instance?: any) { - return new Set(json.wrap); - } - }; - - class TestClass { - @autoserializeAs(Serializer) children: Set = new Set(); - } - - it("will be serialized", () => { - const instance = new TestClass(); - JSON.children.wrap.forEach(v => instance.children.add(v)); - const json = Serialize(instance); - expect(json).toEqual(JSON); - }); - - it("will be deserialized", () => { - const result = Deserialize(JSON, TestClass); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children.wrap); - }); - - it("will be deserializedInto", () => { - const result = DeserializeInto(JSON, TestClass, new TestClass()); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children.wrap); - }); - - }); - - describe('should handle primitive arrays', function () { - - it('should handle serializing a primitive array', function () { - var t = new Test3(); - t.primitiveArray = [1, 2, 3]; - var result = Serialize(t); - expect(result.primitiveArray.length).toBe(3); - expect(result.primitiveArray[0]).toBe(1); - expect(result.primitiveArray[1]).toBe(2); - expect(result.primitiveArray[2]).toBe(3); - }); - - it('should handle deserializing a primitive array', function () { - var t = new Test3(); - t.primitiveArray = [1, 2, 3]; - var result = Deserialize({primitiveArray: [1, 2, 3]}, Test3); - expect(Array.isArray(result.primitiveArray)).toBe(true); - }); - - }); - - describe('to plain array data', () => { - - const JSON = { - children: [11, 22, 33] - }; - - - const Serializer = { - Serialize(_set: Set){ - return Utility.unpackSet(_set); - }, - Deserialize(json: any, instance?: any) { - return new Set(json); - } - }; - - class TestClass { - @autoserializeAs(Serializer) children: Set = new Set(); - } - - it("will be serialized", () => { - const instance = new TestClass(); - JSON.children.forEach(v => instance.children.add(v)); - const json = Serialize(instance); - expect(json).toEqual(JSON); - }); - - it("will be deserialized", () => { - const result = Deserialize(JSON, TestClass); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children); - }); - - it("will be deserializedInto", () => { - const result = DeserializeInto(JSON, TestClass, new TestClass()); - expect(result instanceof TestClass).toBeTruthy(); - expect(result.children instanceof Set).toBeTruthy(); - expect(Utility.unpackSet(result.children)).toEqual(JSON.children); - }); - - }); - -}); diff --git a/spec/deserialize.spec.ts b/spec/deserialize.spec.ts new file mode 100644 index 0000000..2d94d2d --- /dev/null +++ b/spec/deserialize.spec.ts @@ -0,0 +1,1106 @@ +import { + autoserializeAs, + autoserializeAsArray, + autoserializeAsJson, + autoserializeAsMap, + autoserializeUsing, + Deserialize, + deserializeAs, + deserializeAsArray, + deserializeAsJson, + deserializeAsMap, + deserializeUsing, SetDeserializeKeyTransform, + SetDefaultInstantiationMethod +} from "../src"; +import {InstantiationMethod, Indexable, JsonObject} from "../src/util"; + +function expectInstance(instance : any, type : any, instantiationMethod : InstantiationMethod) { + switch (instantiationMethod) { + case InstantiationMethod.New: + case InstantiationMethod.ObjectCreate: + expect(instance instanceof type).toBe(true); + break; + + case InstantiationMethod.None: + expect(instance instanceof type).toBeFalsy(); + expect(instance.toString()).toBe("[object Object]"); + break; + } +} + +function expectTarget(target : any, instance : any, shouldMakeTarget : boolean) { + expect(instance === target).toBe(shouldMakeTarget); +} + +function createTarget(shouldMakeTarget : boolean, shouldinstantiationMethod : InstantiationMethod, type : any) { + if (!shouldMakeTarget) return null; + + switch (shouldinstantiationMethod) { + case InstantiationMethod.New: + return new type(); + + case InstantiationMethod.ObjectCreate: + return Object.create(type.prototype); + + case InstantiationMethod.None: + return {}; + } +} + +describe("Deserializing", function () { + + describe("Unannotated", function () { + + it("will not deserialize unannotated fields", function () { + + class Test { + value : number = 1; + } + + const instance = Deserialize({ value: 2 }, Test); + expect(instance.value).toBe(1); + expect(instance instanceof Test).toBe(true); + + }); + + }); + + describe("DeserializeAs", function () { + + function runTests(blockName : string, instantiationMethod : InstantiationMethod, deserializeAs : any, makeTarget : boolean) { + + describe(blockName, function () { + + it("deserializes basic primitives", function () { + + class Test { + @deserializeAs(String) value0 : string = "strvalue"; + @deserializeAs(Boolean) value1 : boolean = true; + @deserializeAs(Number) value2 : number = 100; + } + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize({ + value0: "strvalue1", + value1: false, + value2: 101 + }, Test, target, instantiationMethod); + expect(instance.value0).toBe("strvalue1"); + expect(instance.value1).toBe(false); + expect(instance.value2).toBe(101); + expectTarget(instance, target, makeTarget); + expectInstance(instance, Test, instantiationMethod); + + }); + + it("deserializes a Date", function () { + class Test { + @deserializeAs(Date) value0 : Date; + } + + const d = new Date().toString(); + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize({ value0: d }, Test, target, instantiationMethod); + expect(instance.value0 instanceof Date).toBe(true); + expect(instance.value0.toString()).toBe(d); + expectTarget(target, instance, makeTarget); + expectInstance(instance, Test, instantiationMethod); + }); + + it("deserializes a RegExp", function () { + class Test { + @deserializeAs(RegExp) value0 : RegExp; + } + + const d = (new RegExp("/[123]/g")).toString(); + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize({ value0: d }, Test, target, instantiationMethod); + expect(instance.value0 instanceof RegExp).toBe(true); + expect(instance.value0.toString()).toBe(d); + expectTarget(instance, target, makeTarget); + expectInstance(instance, Test, instantiationMethod); + + }); + + it("deserializes a non primitive value", function () { + class Thing { + @deserializeAs(Number) value : number = 1; + } + + class Test { + @deserializeAs(Thing) thing : Thing; + } + + const target = createTarget(makeTarget, instantiationMethod, Test); + if (target) target.thing = createTarget(makeTarget, instantiationMethod, Thing); + const instance = Deserialize({ thing: { value: 2 } }, Test, target, instantiationMethod); + expect(instance.thing.value).toBe(2); + expectTarget(target, instance, makeTarget); + if (target) { + expectTarget(target.thing, instance.thing, makeTarget); + } + expectInstance(instance.thing, Thing, instantiationMethod); + expectInstance(instance, Test, instantiationMethod); + }); + + it("deserializes non matching primitive types", function () { + class Test { + @deserializeAs(Number) value0 : string; + @deserializeAs(String) value1 : boolean; + @deserializeAs(Boolean) value2 : number; + } + + const json = { + value0: 100, + value1: true, + value2: "100" + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.value0).toBe(100); + expect(instance.value1).toBe("true"); + expect(instance.value2).toBe(true); + expectTarget(target, instance, makeTarget); + }); + + it("deserializes with different keys", function () { + class Test { + @deserializeAs(String, "str") value0 : string; + @deserializeAs(Boolean, "bool") value1 : boolean; + @deserializeAs(Number, "num") value2 : number; + } + + const json = { + str: "strval", + bool: true, + num: 100 + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.value0).toBe("strval"); + expect(instance.value1).toBe(true); + expect(instance.value2).toBe(100); + expectTarget(target, instance, makeTarget); + }); + + it("skips undefined keys", function () { + class Test { + @deserializeAs(String) value0 : string = "val"; + @deserializeAs(Boolean) value1 : boolean; + @deserializeAs(Number) value2 : number; + } + + const json : any = { + value0: void 0, + value1: true, + value2: 100 + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + if (instantiationMethod) { + expect(instance.value0).toBe("val"); + } + else { + expect(instance.value0).toBeUndefined(); + } + expect(instance.value1).toBe(true); + expect(instance.value2).toBe(100); + }); + + it("does not skip null keys", function () { + class Test { + @deserializeAs(String) value0 : string = "val"; + @deserializeAs(Boolean) value1 : boolean; + @deserializeAs(Number) value2 : number; + } + + const json : any = { + value0: null, + value1: true, + value2: 100 + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.value0).toBe(null); + expect(instance.value1).toBe(true); + expect(instance.value2).toBe(100); + expectTarget(target, instance, makeTarget); + + }); + + it("deserializes nested types", function () { + class Test { + @deserializeAs(String) value0 : string = "bad"; + @deserializeAs(Boolean) value1 : boolean = false; + @deserializeAs(Number) value2 : number = 1; + } + + class Test0 { + @deserializeAs(Test) test : Test; + } + + const json = { + test: { value0: "str", value1: true, value2: 100 } + }; + const target = createTarget(makeTarget, instantiationMethod, Test0); + if (target) target.test = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test0, target, instantiationMethod); + expectInstance(instance.test, Test, instantiationMethod); + if (target) expectInstance(target.test, Test, instantiationMethod); + expect(instance.test.value0).toBe("str"); + expect(instance.test.value1).toBe(true); + expect(instance.test.value2).toBe(100); + }); + + it("deserializes nullable nested types", function () { + class Test { + @deserializeAs(String) value0 : string = "bad"; + @deserializeAs(Boolean) value1 : boolean = false; + @deserializeAs(Number) value2 : number = 1; + } + + class Test0 { + @deserializeAs(Test) test : Test; + } + + const json = { + test: null + }; + const target = createTarget(makeTarget, instantiationMethod, Test0); + if (target) target.test = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test0, target, instantiationMethod); + expect(instance.test).toBeNull(); + }); + + it("deserializes doubly nested types", function () { + class Test0 { + @deserializeAs(String) value0 : string = "bad"; + @deserializeAs(Boolean) value1 : boolean = false; + @deserializeAs(Number) value2 : number = 1; + } + + class Test1 { + @deserializeAs(Test0) test0 : Test0; + } + + class Test2 { + @deserializeAs(Test1) test1 : Test1; + } + + const json = { + test1: { test0: { value0: "str", value1: true, value2: 100 } } + }; + + const target = createTarget(makeTarget, instantiationMethod, Test2); + if (target) { + target.test1 = createTarget(makeTarget, instantiationMethod, Test1); + if (target.test1) { + target.test1.test0 = createTarget(makeTarget, instantiationMethod, Test0); + } + } + const instance = Deserialize(json, Test2, target, instantiationMethod); + expectInstance(instance.test1, Test1, instantiationMethod); + expectInstance(instance.test1.test0, Test0, instantiationMethod); + if (target) { + expectTarget(target, instance, makeTarget); + expectTarget(target.test1, instance.test1, makeTarget); + expectTarget(target.test1.test0, instance.test1.test0, makeTarget); + } + expect(instance.test1.test0.value0).toBe("str"); + expect(instance.test1.test0.value1).toBe(true); + expect(instance.test1.test0.value2).toBe(100); + }); + + }); + + } + + runTests("Normal > Create Instances > With Target", InstantiationMethod.New, deserializeAs, true); + runTests("Normal > Create Instances > Without Target", InstantiationMethod.New, deserializeAs, false); + runTests("Normal > No Instances > With Target", InstantiationMethod.None, deserializeAs, true); + runTests("Normal > No Instances > Without Target", InstantiationMethod.None, deserializeAs, false); + runTests("Auto > Create Instances > With Target", InstantiationMethod.New, autoserializeAs, true); + runTests("Auto > Create Instances > Without Target", InstantiationMethod.New, autoserializeAs, false); + runTests("Auto > No Instances > With Target", InstantiationMethod.None, autoserializeAs, true); + runTests("Auto > No Instances > Without Target", InstantiationMethod.None, autoserializeAs, false); + + }); + + describe("DeserializeAsMap", function () { + + function runTests(blockName : string, instantiationMethod : InstantiationMethod, deserializeAs : any, deserializeAsMap : any, makeTarget : boolean) { + + describe(blockName, function () { + + it("deserializes a map of primitives", function () { + + class Test { + @deserializeAsMap(Number) values : Indexable; + } + + const json = { values: { v0: 0, v1: 1, v2: 2 } }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.values).toEqual({ v0: 0, v1: 1, v2: 2 }); + expectInstance(instance, Test, instantiationMethod); + expectTarget(target, instance, makeTarget); + + }); + + it("deserializes a map of non primitives", function () { + class TestType { + @deserializeAs(Number) value : number; + + constructor(arg : number) { + this.value = arg; + } + } + + class Test { + @deserializeAsMap(TestType) values : Indexable; + } + + const json = { + values: { + v0: { value: 1 }, + v1: { value: 2 }, + v2: { value: 3 } + } + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.values.v0).toEqual({ value: 1 }); + expect(instance.values.v1).toEqual({ value: 2 }); + expect(instance.values.v2).toEqual({ value: 3 }); + }); + + it("deserializes nested maps", function () { + class TestType { + @deserializeAsMap(Number) value : Indexable; + + constructor(arg : Indexable) { + this.value = arg; + } + } + + class Test { + @deserializeAsMap(TestType) values : Indexable; + } + + const json = { + values: { + v0: { value: { v00: 1, v01: 2 } }, + v1: { value: { v10: 2, v11: 2 } }, + v2: { value: { v20: 3, v21: 2 } } + } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.values).toEqual({ + v0: { value: { v00: 1, v01: 2 } }, + v1: { value: { v10: 2, v11: 2 } }, + v2: { value: { v20: 3, v21: 2 } } + }); + }); + + it("skips undefined keys", function () { + class Test { + @deserializeAsMap(Number) values : Indexable; + } + + const json : any = { + values: { + v0: void 0, + v1: 1, + v2: 2 + } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + values: { + v1: 1, + v2: 2 + } + }); + }); + + it("deserializes a map with different key name", function () { + class TestType { + @deserializeAs(Number) value : number; + + constructor(arg : number) { + this.value = arg; + } + } + + class Test { + @deserializeAsMap(TestType, "different") values : Indexable; + } + + const json = { + different: { v0: { value: 1 }, v1: { value: 2 } } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.values).toEqual({ + v0: { value: 1 }, v1: { value: 2 } + }); + + }); + + it("throws an exeption if input is not a map type", function () { + class Test { + @deserializeAsMap(Number) values : Indexable; + } + + expect(function () { + const json = { values: 1 }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be of type `object` but received: number"); + + expect(function () { + const json = { values: false }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be of type `object` but received: boolean"); + + expect(function () { + const json = { values: "str" }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be of type `object` but received: string"); + + }); + + it("deserializes a null map", function () { + + class Test { + @deserializeAsMap(Number) values : Indexable; + } + + const json : any = { values: null }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance.values).toBeNull(); + + }); + + }); + + } + + runTests("Normal > Create Instances > With Target", InstantiationMethod.New, deserializeAs, deserializeAsMap, true); + runTests("Normal > Create Instances > Without Target", InstantiationMethod.New, deserializeAs, deserializeAsMap, false); + runTests("Normal > No Instances > With Target", InstantiationMethod.None, deserializeAs, deserializeAsMap, true); + runTests("Normal > No Instances > Without Target", InstantiationMethod.None, deserializeAs, deserializeAsMap, false); + runTests("Auto > Create Instances > With Target", InstantiationMethod.New, autoserializeAs, autoserializeAsMap, true); + runTests("Auto > Create Instances > Without Target", InstantiationMethod.New, autoserializeAs, autoserializeAsMap, false); + runTests("Auto > No Instances > With Target", InstantiationMethod.None, autoserializeAs, autoserializeAsMap, true); + runTests("Auto > No Instances > Without Target", InstantiationMethod.None, autoserializeAs, autoserializeAsMap, false); + + }); + + describe("DeserializeAsArray", function () { + + function runTests(blockName : string, instantiationMethod : InstantiationMethod, deserializeAs : any, deserializeAsArray : any, makeTarget : boolean) { + + describe(blockName, function () { + + it("deserializes an array of primitives", function () { + class Test { + @deserializeAsArray(Number) value : Array; + } + + const json = { value: [1, 2, 3] }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(Array.isArray(instance.value)).toBeTruthy(); + expect(instance.value).toEqual([1, 2, 3]); + expectInstance(instance, Test, instantiationMethod); + expectTarget(target, instance, makeTarget); + }); + + it("deserializes an array of typed objects", function () { + class TestType { + @deserializeAs(String) strVal : string; + + constructor(val : string) { + this.strVal = val; + } + } + + class Test { + @deserializeAsArray(TestType) value : Array; + } + + const json = { + value: [ + { strVal: "0" }, + { strVal: "1" }, + { strVal: "2" } + ] + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expectInstance(instance, Test, instantiationMethod); + expectTarget(target, instance, makeTarget); + expect(instance.value).toEqual([ + { strVal: "0" }, + { strVal: "1" }, + { strVal: "2" } + ]); + if (instantiationMethod) { + expect(instance.value[0] instanceof TestType).toBeTruthy(); + expect(instance.value[1] instanceof TestType).toBeTruthy(); + expect(instance.value[2] instanceof TestType).toBeTruthy(); + } + expect(instance.value.length).toBe(3); + }); + + it("deserializes nested arrays", function () { + class TestTypeL0 { + @deserializeAs(String) strVal : string; + + constructor(val : string) { + this.strVal = val; + } + + } + + class TestTypeL1 { + @deserializeAsArray(TestTypeL0) l0List : Array; + + constructor(l0List : TestTypeL0[]) { + this.l0List = l0List; + } + + } + + class Test { + @deserializeAsArray(TestTypeL1) value : Array; + } + + const json = { + value: [ + { l0List: [{ strVal: "00" }, { strVal: "01" }] }, + { l0List: [{ strVal: "10" }, { strVal: "11" }] }, + { l0List: [{ strVal: "20" }, { strVal: "21" }] } + ] + }; + + const array = [ + new TestTypeL1([new TestTypeL0("00"), new TestTypeL0("01")]), + new TestTypeL1([new TestTypeL0("10"), new TestTypeL0("11")]), + new TestTypeL1([new TestTypeL0("20"), new TestTypeL0("21")]) + ]; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ value: array }); + if (instantiationMethod) { + expect(instance.value[0] instanceof TestTypeL1).toBeTruthy(); + expect(instance.value[1] instanceof TestTypeL1).toBeTruthy(); + expect(instance.value[2] instanceof TestTypeL1).toBeTruthy(); + } + + }); + + it("deserializes an array with a different key", function () { + + class Test { + @deserializeAsArray(Number, "different") value : Array; + } + + const json = { different: [1, 2, 3] }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expectInstance(instance, Test, instantiationMethod); + expectTarget(target, instance, makeTarget); + expect(instance).toEqual({ + value: [1, 2, 3] + }); + }); + + it("throws an error if input type is not an array", function () { + + class Test { + @deserializeAsArray(Number) values : Array; + } + + expect(function () { + const json = { values: 1 }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be an array but received: number"); + + expect(function () { + const json = { values: false }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be an array but received: boolean"); + + expect(function () { + const json = { values: "str" }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be an array but received: string"); + + expect(function () { + const json = { values: {} }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + }).toThrow("Expected input to be an array but received: object"); + + }); + + }); + + } + + runTests("Normal > Create Instances > With Target", InstantiationMethod.New, deserializeAs, deserializeAsArray, true); + runTests("Normal > Create Instances > Without Target", InstantiationMethod.New, deserializeAs, deserializeAsArray, false); + runTests("Normal > No Instances > With Target", InstantiationMethod.None, deserializeAs, deserializeAsArray, true); + runTests("Normal > No Instances > Without Target", InstantiationMethod.None, deserializeAs, deserializeAsArray, false); + runTests("Auto > Create Instances > With Target", InstantiationMethod.New, autoserializeAs, autoserializeAsArray, true); + runTests("Auto > Create Instances > Without Target", InstantiationMethod.New, autoserializeAs, autoserializeAsArray, false); + runTests("Auto > No Instances > With Target", InstantiationMethod.None, autoserializeAs, autoserializeAsArray, true); + runTests("Auto > No Instances > Without Target", InstantiationMethod.None, autoserializeAs, autoserializeAsArray, false); + + }); + + describe("DeserializeJSON", function () { + + function runTests(blockName : string, instantiationMethod : InstantiationMethod, deserializeAs : any, deserializeAsJson : any, makeTarget : boolean) { + + describe(blockName, function () { + + it("deserializes a primitive as json", function () { + + class Test { + @deserializeAsJson() value0 : string; + @deserializeAsJson() value1 : boolean; + @deserializeAsJson() value2 : number; + } + + const json = { + value0: "strval", + value1: true, + value2: 1 + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + value0: "strval", + value1: true, + value2: 1 + }); + + }); + + it("deserializes an array of primitives as json", function () { + + class Test { + @deserializeAsJson() value0 : string[]; + @deserializeAsJson() value1 : boolean[]; + @deserializeAsJson() value2 : number; + } + + const json = { + value0: ["strvalue", "00"], + value1: [false, true], + value2: 100 + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + value0: ["strvalue", "00"], + value1: [false, true], + value2: 100 + }); + + }); + + it("skips undefined keys", function () { + class Test { + @deserializeAsJson() value : Indexable; + } + + const json : any = { + value: { + v0: 1, + v1: void 0, + v2: 2 + } + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + value: { + v0: 1, + v2: 2 + } + }); + + }); + + it("deserializes an array of non primitives as json", function () { + + class Test { + @deserializeAsJson() things : any[]; + + } + + const json = { + things: [ + { x: 1, y: 3 }, + { x: 2, y: 2 }, + { x: 3, y: 1 }, + ] + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: [ + { x: 1, y: 3 }, + { x: 2, y: 2 }, + { x: 3, y: 1 }, + ] + }); + }); + + it("deserializes a map of primitives as json", function () { + class Test { + @deserializeAsJson() things : any; + + } + + const json = { + things: { + x: 1, y: 2, z: 3 + } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: { x: 1, y: 2, z: 3 } + }); + expect(instance.things).not.toBe(json); + }); + + it("deserializes a map of non primitives as json", function () { + class Test { + @deserializeAsJson() things : any; + + } + + const json = { + things: { + v0: { x: 1, y: 3 }, + v1: { x: 2, y: 2 }, + v2: { x: 3, y: 1 }, + } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: { + v0: { x: 1, y: 3 }, + v1: { x: 2, y: 2 }, + v2: { x: 3, y: 1 }, + } + }); + expect(instance.things).not.toBe(json); + }); + + it("deserializes nested arrays", function () { + class Test { + @deserializeAsJson() things : any; + + } + + const json = { + things: [ + [1, 2, 3], + [4, 5, 6] + ] + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: [ + [1, 2, 3], + [4, 5, 6] + ] + }); + expect(instance.things).not.toBe(json); + }); + + it("does not deserialize functions", function () { + class Test { + @deserializeAsJson() things : any; + + } + + const json : any = { + things: [], + fn: function () {} + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: [] + }); + expect((instance as any).fn).toBeUndefined(); + expect(instance.things).not.toBe(json); + }); + + it("deserializes json with a different key", function () { + class Test { + @deserializeAsJson("something") things : any; + + } + + const json = { + something: { + x: 1, y: 2, z: 3 + } + }; + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expect(instance).toEqual({ + things: { x: 1, y: 2, z: 3 } + }); + }); + + it("applies key transforms by default", function () { + SetDeserializeKeyTransform(function (value) { + return value.toUpperCase(); + }); + + class Test { + @deserializeAsJson() value0 : string; + @deserializeAsJson() value1 : boolean; + @deserializeAsJson() value2 : number; + } + + const json = { + VALUE0: "strvalue", + VALUE1: true, + VALUE2: 100 + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + SetDeserializeKeyTransform(null); + expect(instance).toEqual({ + value0: "strvalue", + value1: true, + value2: 100 + }); + }); + + it("applies key transforms when set to true", function () { + SetDeserializeKeyTransform(function (value) { + return value.toUpperCase(); + }); + + class Test { + @deserializeAsJson(true) value0 : string; + @deserializeAsJson(true) value1 : boolean; + @deserializeAsJson(true) value2 : number; + } + + const json = { + VALUE0: "strvalue", + VALUE1: true, + VALUE2: 100 + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + SetDeserializeKeyTransform(null); + expect(instance).toEqual({ + value0: "strvalue", + value1: true, + value2: 100 + }); + }); + + xit("does not apply key transforms when set to false", function () { + + }); + + }); + } + + runTests("Normal > Create Instances > With Target", InstantiationMethod.New, deserializeAs, deserializeAsJson, true); + runTests("Normal > Create Instances > Without Target", InstantiationMethod.New, deserializeAs, deserializeAsJson, false); + runTests("Normal > No Instances > With Target", InstantiationMethod.None, deserializeAs, deserializeAsJson, true); + runTests("Normal > No Instances > Without Target", InstantiationMethod.None, deserializeAs, deserializeAsJson, false); + runTests("Auto > Create Instances > With Target", InstantiationMethod.New, autoserializeAs, autoserializeAsJson, true); + runTests("Auto > Create Instances > Without Target", InstantiationMethod.New, autoserializeAs, autoserializeAsJson, false); + runTests("Auto > No Instances > With Target", InstantiationMethod.None, autoserializeAs, autoserializeAsJson, true); + runTests("Auto > No Instances > Without Target", InstantiationMethod.None, autoserializeAs, autoserializeAsJson, false); + + }); + + describe("DeserializeUsing", function () { + + function runTests(blockName : string, instantiationMethod : InstantiationMethod, deserializeAs : any, deserializeUsing : any, makeTarget : boolean) { + + it("uses the provided function", function () { + function x(value : any) { return 1; } + + class Test { + @deserializeUsing(x) value : number = 10; + @autoserializeUsing({ Serialize: x, Deserialize: x }) value1 : string; + } + + const json = { + value: "yes", + value1: "hello" + }; + + const target = createTarget(makeTarget, instantiationMethod, Test); + const instance = Deserialize(json, Test, target, instantiationMethod); + expectTarget(target, instance, makeTarget); + expectInstance(instance, Test, instantiationMethod); + expect(instance).toEqual({ value: 1, value1: 1 }); + + }); + + } + + runTests("Normal > Create Instances > With Target", InstantiationMethod.New, deserializeAs, deserializeUsing, true); + runTests("Normal > Create Instances > Without Target", InstantiationMethod.New, deserializeAs, deserializeUsing, false); + runTests("Normal > No Instances > With Target", InstantiationMethod.None, deserializeAs, deserializeUsing, true); + runTests("Normal > No Instances > Without Target", InstantiationMethod.None, deserializeAs, deserializeUsing, false); + + }); + + describe("onDeserialized", function () { + + it("invokes the handler if provided", function () { + + class Test { + + @deserializeAs(Number) value : number = 1; + something : string; + + static onDeserialized(json : JsonObject, instance : Test) { + instance.something = "here"; + } + + } + + const json = { value: 100 }; + const instance = Deserialize(json, Test, null, InstantiationMethod.New); + expect(instance).toEqual({ + something: "here", + value: 100 + }); + + }); + + it("accepts the return value of onDeserialized if provided", function () { + + class Test { + + @deserializeAs(Number) value : number = 1; + something : string; + + static onDeserialized(json : JsonObject, instance : Test) { + const retn = new Test(); + retn.value = 300; + retn.something = "here"; + return retn; + } + + } + + const json = { value: 100 }; + const instance = Deserialize(json, Test, null, InstantiationMethod.New); + expect(instance).toEqual({ + something: "here", + value: 300 + }); + }); + + }); + + describe("InstantiationMethod", function () { + + it("New", function () { + + class Test { + + constructed : boolean = false; + + constructor() { + this.constructed = true; + } + + } + + const json = {}; + const instance = Deserialize(json, Test, null, InstantiationMethod.New); + expect(instance).toEqual({ + constructed: true + }); + + }); + + it("ObjectCreate", function () { + + class Test { + + constructed : boolean; + + constructor() { + this.constructed = true; + } + + } + + const json = {}; + const instance = Deserialize(json, Test, null, InstantiationMethod.ObjectCreate); + expect(instance.constructed).toBeUndefined(); + + }); + + it("None", function () { + + class Test { + } + + const json = {}; + const instance = Deserialize(json, Test, null, InstantiationMethod.None); + expect(typeof instance).toEqual('object'); + expect(instance instanceof Test).toEqual(false); + }); + + it("SetDefaultInstantiationMethod", function () { + SetDefaultInstantiationMethod(InstantiationMethod.None); + + class Test { + } + + const json = {}; + const instance = Deserialize(json, Test, null, InstantiationMethod.None); + + SetDefaultInstantiationMethod(null); // Reset. + + expect(typeof instance).toEqual('object'); + expect(instance instanceof Test).toEqual(false); + }); + + }); + +}); \ No newline at end of file diff --git a/spec/deserialize_annotation_spec.ts b/spec/deserialize_annotation_spec.ts deleted file mode 100644 index a0d9d19..0000000 --- a/spec/deserialize_annotation_spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -/// -import { __TypeMap, deserialize, deserializeAs, Deserialize } from '../src/serialize'; - - -class T { - @deserialize public x : number; -} - -class Vector2 { - @deserialize x : number; - @deserialize y : number; -} - -class AsTest { - @deserializeAs(Vector2) v : Vector2; -} - -class AsTest2 { - @deserializeAs(Vector2, "VECTOR") v : Vector2; -} - -class AsTest3 { - @deserializeAs("z") y : number; -} - -describe('deserialize', function () { - - it('should create meta data', function() { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - }); -}); - -describe('serializeAs', function() { - it('should create meta data', function() { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].deserializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].deserializedType).toBe(Vector2); - }); - - it('should create meta data with a different key', function() { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].deserializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].deserializedType).toBe(null); - }); - - it('should create meta data with a different key and type', function() { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].deserializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].deserializedType).toBe(Vector2); - }); -}); - diff --git a/spec/deserialize_function_spec.ts b/spec/deserialize_function_spec.ts deleted file mode 100644 index 4b561c1..0000000 --- a/spec/deserialize_function_spec.ts +++ /dev/null @@ -1,427 +0,0 @@ -/// -import { - deserialize, deserializeAs, Deserialize, GenericDeserialize, - GenericDeserializeInto, deserializeIndexable -} from '../src/serialize'; - -class T1 { - public x : number; - public y : number; -} - -class T2 { - @deserialize public x : number; - @deserialize public y : number; - - public static OnDeserialized() : void { - } -} - -class T3 { - @deserializeAs(T2) child : T2; - @deserialize x : number; - - public static OnDeserialized() : void { - } -} - -class T4 { - @deserializeAs(Date) dateList : Array; -} - -class T5 { - @deserializeAs(Date) date: Date; -} - -class JsonTest { - @deserialize public obj : any; - - constructor() { - this.obj = { - key1: 1, - nestedKey : { - key2: 2 - } - } - } -} - -class Fruit { - @deserialize public name: string; -} - -class Tree { - @deserialize public value: string; - @deserializeAs(Fruit) fruits: Array; - @deserializeAs(Tree) trees: Array; -} - -var DeserializerFn = function(src : any) : any { - return 'custom!'; -}; - -var Deserializer = { - Deserialize: DeserializerFn -}; - -class CustomDeserializeTest { - @deserializeAs(Deserializer) public x : string; -} - -class CustomDeserializeTest2 { - @deserializeAs(DeserializerFn) public x : string; -} - -describe('Deserialize', function () { - - it('should not deserialize if not marked with deserializer', function () { - var json = { x: 1, y: 2 }; - var instance = Deserialize(json, T1); - expect((instance instanceof T1)).toBe(true); - expect(instance.x).toBeUndefined(); - expect(instance.y).toBeUndefined(); - }); - - it('should deserialize if marked with deserializer', function () { - var json = { x: 1, y: 2 }; - var instance = Deserialize(json, T2); - expect((instance instanceof T2)).toBe(true); - expect(instance.x).toBe(1); - expect(instance.y).toBe(2); - }); - - it('should deserialize an array', function () { - var json = [{ x: 1, y: 1 }, { x: 2, y: 2 }]; - var list = Deserialize(json, T2); - expect(Array.isArray(list)); - expect(list.length).toBe(2); - expect(list[0] instanceof T2).toBe(true); - expect(list[0].x).toBe(1); - expect(list[0].y).toBe(1); - expect(list[1] instanceof T2).toBe(true); - expect(list[1].x).toBe(2); - expect(list[1].y).toBe(2); - }); - - it('should deserialize a primitive', function () { - expect(Deserialize(1)).toBe(1); - expect(Deserialize(null)).toBe(null); - expect(Deserialize(false)).toBe(false); - expect(Deserialize(true)).toBe(true); - expect(Deserialize('1')).toBe('1'); - }); - - it('should deserialize a date', function () { - var d = new Date(); - var dateStr = d.toString(); - var result = Deserialize(dateStr, Date); - expect(result instanceof Date).toBe(true); - }); - - it('should deserialize a date even when it\'s not a string', function () { - var d = new Date(); - var result = Deserialize(d, Date); - expect(result instanceof Date).toBe(true); - expect(result.toString()).toEqual(d.toString()) - }); - - it('should deserialize a regex', function () { - var r = /hi/; - var regexStr = r.toString(); - var result = Deserialize(regexStr, RegExp); - expect(result instanceof RegExp).toBe(true); - }); - - it('should deserialize a nested object as a type', function () { - var t3 = { child: { x: 1, y: 1 }, x: 2 }; - var result = Deserialize(t3, T3); - expect(result instanceof T3).toBe(true); - expect(result.child instanceof T2).toBe(true); - expect(result.child.x).toBe(1); - expect(result.child.y).toBe(1); - expect(result.x).toBe(2); - }); - - it('should deserialize a nested array as a type', function () { - var d1 = new Date(); - var d2 = new Date(); - var d3 = new Date(); - var t4 = { dateList: [d1.toString(), d2.toString(), d3] }; - var result = Deserialize(t4, T4); - expect(result instanceof T4).toBeTruthy(); - expect(Array.isArray(result.dateList)).toBe(true); - expect(result.dateList[0].toString()).toEqual(d1.toString()); - expect(result.dateList[1].toString()).toEqual(d2.toString()); - expect(result.dateList[2].toString()).toEqual(d3.toString()); - }); - - it('should deserialize a Date property even if source is a Date object', function () { - var t5 = { date: new Date() } - var result = Deserialize(t5, T5); - expect(result instanceof T5).toBeTruthy(); - expect(result.date.toString()).toEqual(t5.date.toString()); - }); - - it('should call OnDeserialize if defined on parent and or child', function () { - var json = { - child: {x : 1, y: 1}, - x: 10 - }; - spyOn(T3, 'OnDeserialized').and.callThrough(); - spyOn(T2, 'OnDeserialized').and.callThrough(); - - var result = Deserialize(json, T3); - - expect(T3.OnDeserialized).toHaveBeenCalledWith(result, json); - expect(T2.OnDeserialized).toHaveBeenCalledWith(result.child, json.child); - }); - - it('should deserialize js objects tagged with deserialize', function(){ - var testJson = new JsonTest(); - var result = Deserialize(testJson, JsonTest); - expect(result).toBeDefined(); - expect(typeof result.obj === "object").toBeTruthy(); - expect(result.obj.key1).toBe(1); - expect(result.obj.nestedKey.key2).toBe(2); - }); - - it('should deserialize js primitive arrays tagged with deserialize', function() { - - }); - - it('should use a custom deserializer', function() { - var testJson = { - "x": new Date().toString() - }; - var result = Deserialize(testJson, CustomDeserializeTest); - expect(result.x).toBe("custom!"); - }); - - it('should use a custom deserialize function', function() { - var testJson = { - "x": new Date().toString() - }; - var result = Deserialize(testJson, CustomDeserializeTest2); - expect(result.x).toBe("custom!"); - }); - - it('should cast to primitive array when given a primitive type', function() { - class Test { - @deserializeAs(String) public arrayOfString: Array; - @deserializeAs(Number) public arrayOfNumber: Array; - @deserializeAs(Boolean) public arrayOfBoolean: Array; - } - var json = { - arrayOfString: ['String1', 'String2'], - arrayOfNumber: [1, 2], - arrayOfBoolean: [true, false] - }; - - var test : Test = Deserialize(json, Test); - expect(Array.isArray(test.arrayOfString)).toBe(true); - expect(test.arrayOfString[0]).toBe("String1"); - expect(test.arrayOfString[1]).toBe("String2"); - expect(Array.isArray(test.arrayOfNumber)).toBe(true); - expect(test.arrayOfNumber[0]).toBe(1); - expect(test.arrayOfNumber[1]).toBe(2); - expect(Array.isArray(test.arrayOfBoolean)).toBe(true); - expect(test.arrayOfBoolean[0]).toBe(true); - expect(test.arrayOfBoolean[1]).toBe(false); - }); - - it('should cast to primitive type when given a primitive type', function() { - class Test { - @deserializeAs(String) public str: string; - @deserializeAs(Number) public num: number; - @deserializeAs(Boolean) public bool: boolean; - @deserializeAs(Number) public float: number; - } - var json = { - str: 1, - num: "2", - bool: 3, - float: "3.1415" - }; - - var test : Test = Deserialize(json, Test); - expect(test.str).toBe('1'); - expect(test.num).toBe(2); - expect(test.bool).toBe(true); - expect(test.float).toBe(3.1415); - }); - - //contributed by @1ambda - it('should deserialize a json including nested empty arrays', function() { - var root1 = { - trees: new Array(), - value: "root1" - }; - - var deserialized1 = Deserialize(root1, Tree); - expect(deserialized1.trees.length).toBe(0); - expect(deserialized1.value).toBe("root1"); - - /** - * `-- root - * |-- t1 - * `-- t2 - * |-- t3 - * `-- t4 - */ - - var root2 = { - trees: [{ - value: "t1" , - trees: new Array() - }, { - value: "t2", - trees: [{ - value: "t3", - trees: new Array() - }, { - value: "t4", - trees: new Array() - }] - }], - value: "root2" - }; - - var deserialized2 = Deserialize(root2, Tree); - expect(deserialized2.trees.length).toBe(2); - expect(deserialized2.trees[0].trees.length).toBe(0); /* t1 includes empty trees */ - expect(deserialized2.trees[1].trees.length).toBe(2); /* t2 includes 2 trees (t3, t4) */ - }); - - it("should deserialize custom objects into an array", function() { - // class Item { } - }) - - it("should deserialize empty json into an empty string") - - it('should deserialize a json including nested, multiple empty arrays', function() { - var root1 = { - fruits: new Array(), - trees: new Array(), - value: "root1" - }; - - var deserialized1 = Deserialize(root1, Tree); - expect(deserialized1.trees.length).toBe(0); - expect(deserialized1.value).toBe("root1"); - expect(deserialized1.fruits.length).toBe(0); - - /** - * `-- root - * |-- t1 including f1 - * `-- t2 - * |-- t3 including f3 - * `-- t4 - */ - - var root2 = { - trees: [{ - value: "t1" , - trees: new Array(), - fruits: new Array(), - }, { - value: "t2", - trees: [{ - value: "t3", - trees: new Array(), - fruits: new Array(), - }, { - value: "t4", - trees: new Array() - }] - }], - value: "root2" - }; - - var deserialized2 = Deserialize(root2, Tree); - expect(deserialized2.trees.length).toBe(2); - expect(deserialized2.trees[0].trees.length).toBe(0); /* t1 includes empty trees */ - expect(deserialized2.trees[0].fruits.length).toBe(0); /* t1 includes empty fruits */ - expect(deserialized2.trees[1].trees.length).toBe(2); /* t2 includes 2 trees (t3, t4) */ - expect(deserialized2.trees[1].trees[0].trees.length).toBe(0); /* t3 includes empty trees */ - expect(deserialized2.trees[1].trees[0].fruits.length).toBe(0); /* t3 includes fruits trees */ - expect(deserialized2.trees[1].trees[1].trees.length).toBe(0); /* t4 includes empty trees */ - expect(deserialized2.trees[1].trees[1].fruits).toBeUndefined(); /* t4 has no fruits */ - }); - - it("Should deserialize indexable object", function () { - - class Y { - @deserialize thing : string; - } - - class X { - @deserializeIndexable(Y) yMap : any; - } - - var map : any = { - yMap: { - 1: { thing: '1' }, - 2: { thing: '2' } - } - }; - - var x : X = Deserialize(map, X); - expect(x.yMap[1] instanceof(Y)).toBe(true); - expect(x.yMap[2] instanceof(Y)).toBe(true); - }); - -}); - -describe('Deserialize generics', function () { - - it('should handle a generic deserialize', function () { - var tree = GenericDeserialize({value: "someValue"}, Tree); - expect((tree instanceof Tree)).toBe(true); - expect(tree.value).toBe("someValue"); - }); - - it('should handle a generic deserializeInto', function () { - var tree = new Tree(); - tree.value = 'hello'; - var tree2 = GenericDeserializeInto({value: "someValue"}, Tree, tree); - expect((tree2 instanceof Tree)).toBe(true); - expect(tree2).toBe(tree); - expect(tree.value).toBe("someValue"); - }); - -}); - -//rest of file contributed by @1ambda -export interface NoParamConstructor { - new (): T -} - -export abstract class Deserializable { - public static deserialize(ctor: NoParamConstructor, json : any): T { - return Deserialize(json, ctor); - } - - public static deserializeArray(ctor: NoParamConstructor, json : any): Array { - return Deserialize(json, ctor); - } -} - -class Car extends Deserializable { - @deserialize public engine: string; - @deserialize public wheels: number; -} - -describe("Deserializable", () => { - describe("deserialize", () => { - it("should parse Car", () => { - let json : any = {engine: "M5", wheels: 4}; - let c1 = Car.deserialize(Car, json); - let c2 = Car.deserialize(Car, json); // without NoParamConstructor - - expect(c1.engine).toEqual(json.engine); - expect(c1.wheels).toEqual(json.wheels); - }); - }); - - -}); diff --git a/spec/deserialize_into_spec.ts b/spec/deserialize_into_spec.ts deleted file mode 100644 index b261a6f..0000000 --- a/spec/deserialize_into_spec.ts +++ /dev/null @@ -1,283 +0,0 @@ -/// -import { - deserialize, - deserializeAs, - deserializeIndexable, - autoserializeAs, - DeserializeInto -} from '../src/serialize'; - -class T1 { - -} - -class T2 { - @deserialize public x : number; - public y : number; - - constructor(x : number, y : number) { - this.x = x; - this.y = y; - } -} - -class T3 { - @deserializeAs(T2) public list : Array; - - constructor(list : Array) { - this.list = list; - } -} - -class T4 { - @deserializeAs(T3, 'T3') t3 : T3; - @autoserializeAs(Date) public date : Date; -} - -class JsonSubArrayTest { - @deserialize public obj : any; - - constructor() { - this.obj = { - array: [{ x: 1 }, { x: 2 }] - } - } -} - -class JSONSubObjectTest { - @deserialize public obj : any; - - constructor() { - this.obj = { - subobject: { - a: 1, - b: 2 - } - } - } -} - -class ArrayItem { - @deserialize public x : string; - - constructor(x : string) { - this.x = x; - } -} - -class TypedNestedArrayTest { - @deserializeAs(ArrayItem) public children : ArrayItem[]; -} - -class NestedArrayTest { - @deserialize public children : string[]; -} - -class NestedArrayOfObjectsTest { - @deserialize public children : Array; -} - -var CustomDeserializer = { - Deserialize: function (src : any) : any { - return 'custom!'; - } -}; - -class CustomDeserialized { - @deserializeAs(CustomDeserializer) public x : string; -} - -describe('DeserializeInto', function () { - it('should return the same instance passed to it', function () { - var instance = new T1(); - expect(DeserializeInto({}, T1, instance)).toBe(instance); - }); - - it('will create a new instance of Type if instance argument is null', function () { - expect(DeserializeInto({}, T1, null) instanceof T1).toBe(true); - }); - - it('will deserialize into an array of Type if instance is an array', function () { - var instanceArray : Array = []; - var result = DeserializeInto([{}, {}], T1, instanceArray); - expect(Array.isArray(result)).toBe(true); - expect(result.length).toBe(2); - expect(result[0] instanceof T1).toBe(true); - expect(result[1] instanceof T1).toBe(true); - }); - - it('will only deserialized fields marked for deserialization', function () { - var json = { x: 10, y: 20 }; - var instance = new T2(1, 2); - var result = DeserializeInto(json, T2, instance); - expect(result.x).toBe(10); - expect(result.y).toBe(2); - }); - - it('will deserialize an array property and preserve instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }, { x: 20, y: 20 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(2); - expect(instance.list[0]).toBe(test1); - expect(instance.list[1]).toBe(test2); - expect(test1.x).toBe(10); - expect(test1.y).toBe(1); - expect(test2.x).toBe(20); - expect(test2.y).toBe(2); - }); - - it('will deserialize an array property and truncate instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(1); - expect(instance.list[0]).toBe(test1); - expect(test1.x).toBe(10); - expect(test1.y).toBe(1); - }); - - it('will deserialize an array property and create instances', function () { - var test1 = new T2(1, 1); - var test2 = new T2(2, 2); - var instance = new T3([test1, test2]); - var originalList = instance.list; - var json = { - list: [{ x: 10, y: 10 }, { x: 20, y: 20 }, { x: 30, y: 30 }] - }; - instance = DeserializeInto(json, T3, instance); - expect(instance.list).toBe(originalList); - expect(instance.list.length).toBe(3); - expect(instance.list[0]).toBe(test1); - expect(instance.list[1]).toBe(test2); - expect(instance.list[2] instanceof T2).toBe(true); - expect(originalList[2].x).toBe(30); - expect(originalList[2].y).toBe(void 0); - }); - - it('will deserialize an object with nested deserialized properties', function () { - var instance = new T4(); - instance.t3 = new T3([]); - var d = new Date(); - instance.date = d; - var json = { - date: new Date().toString(), - T3: { - list: [{ x: 1 }, { x: 2 }] - } - }; - var result = DeserializeInto(json, T4, instance); - expect(result.t3.list[0].x).toBe(1); - expect(result.date).toBe(d); - }); - - it('should deserialize arrays in untyped objects tagged with deserialize', function () { - var source = new JsonSubArrayTest(); - var json = { obj: { array: [{ x: 3 }, { x: 4 }, { x: 5 }] } }; - var result = DeserializeInto(json, JsonSubArrayTest, source); - expect(result).toEqual(source); - expect(result).toBeDefined(); - expect(typeof result.obj === "object").toBeTruthy(); - expect(result.obj.array.length).toBe(3); - expect(result.obj.array[0]).toEqual(source.obj.array[0]); - expect(result.obj.array[1]).toEqual(source.obj.array[1]); - expect(result.obj.array[0].x).toEqual(3); - expect(result.obj.array[1].x).toEqual(4); - expect(result.obj.array[2].x).toEqual(5); - }); - - it('should deserialize sub-objects in untyped objects tagged with deserialize', function () { - var source = new JSONSubObjectTest(); - var originalSubObject = source.obj.subobject; - expect(source.obj.subobject.c).toBeUndefined(); - var json = { obj: { subobject: { a: 10, b: 20, c: 30 } } }; - var result = DeserializeInto(json, JSONSubObjectTest, source); - expect(result).toEqual(source); - expect(result.obj.subobject).toEqual(originalSubObject); - expect(result.obj.subobject.a).toEqual(10); - expect(result.obj.subobject.b).toEqual(20); - expect(result.obj.subobject.c).toEqual(30); - }); - - it('should deserialize with a custom deserializer', function () { - var testJson = { - "x": new Date().toString() - }; - var result = DeserializeInto(testJson, CustomDeserialized, null); - expect(result.x).toBe("custom!"); - }); - - it('will deserialize js nested primitive array tagged with deserialize', function () { - var json = { children: ["1", "2", "3", "4"] }; - var result = DeserializeInto(json, NestedArrayTest, new NestedArrayTest()); - expect(result.children).toEqual(["1", "2", "3", "4"]); - expect(result instanceof NestedArrayTest).toBe(true); - }); - - it('will deserialize nested non primitive array tagged with deserialize', function () { - var json = { children: [{ x: "1" }, { x: "2" }, { x: "3" }, { x: "4" }] }; - var result = DeserializeInto(json, TypedNestedArrayTest, new TypedNestedArrayTest()); - expect(result.children[0].x).toEqual("1"); - expect(result.children[1].x).toEqual("2"); - expect(result.children[2].x).toEqual("3"); - expect(result.children[3].x).toEqual("4"); - expect(result.children[0] instanceof ArrayItem).toBe(true); - expect(result.children[1] instanceof ArrayItem).toBe(true); - expect(result.children[2] instanceof ArrayItem).toBe(true); - expect(result.children[3] instanceof ArrayItem).toBe(true); - }); - - it("will deserialized neseted object array tagged with deserialize", function () { - var original = new NestedArrayOfObjectsTest(); - original.children = [{ x: "10" }, { x: "20" }, { x: "30" }]; - var json = { children: [{ x: "1" }, { x: "2" }, { x: "3" }, { x: "4" }] }; - var result = DeserializeInto(json, NestedArrayOfObjectsTest, new NestedArrayOfObjectsTest()); - expect(result.children.length).toEqual(4); - expect(result.children[0].x).toEqual("1"); - expect(result.children[1].x).toEqual("2"); - expect(result.children[2].x).toEqual("3"); - expect(result.children[3].x).toEqual("4"); - }); - - it("Should deserialize indexable object", function () { - - class Y { - @deserialize thing : string; - } - - class X { - @deserializeIndexable(Y) yMap : any; - - constructor() { - this.yMap = {}; - } - } - - var map : any = { - yMap: { - 1: { thing: '1' }, - 2: { thing: '2' } - } - }; - - var x = new X(); - var yMap = x.yMap; - DeserializeInto(map, X, x); - expect(x.yMap).toBe(yMap); - expect(x.yMap[1] instanceof (Y)).toBe(true); - expect(x.yMap[2] instanceof (Y)).toBe(true); - }); -}); - diff --git a/spec/enum_spec.ts b/spec/enum_spec.ts deleted file mode 100644 index 221418b..0000000 --- a/spec/enum_spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// -import { - autoserialize, - autoserializeAs, - Serialize, - Deserialize, - DeserializeInto, - SerializableEnumeration -} from '../src/serialize'; - -enum TestEnum { - One = 1 << 0, - Two = 1 << 1, - Three = 1 << 2 -} - -SerializableEnumeration(TestEnum); - -class T1 { - @autoserializeAs(TestEnum) public e : TestEnum; -} - -describe('Enums', function() { - - it('should serialize an enum', function () { - var t1 = new T1(); - t1.e = TestEnum.One; - var result = Serialize(t1); - expect(result.e).toBe("One"); - }); - - it('should deserialize an enum', function () { - var json = { - e : "One" - }; - var result = Deserialize(json, T1); - expect(result.e).toBe(TestEnum.One); - }); - - it('should deserializeInto an enum', function () { - var json = { - e : "One" - }; - var t1 = new T1(); - var result = DeserializeInto(json, T1, t1); - expect(result.e).toBe(TestEnum.One); - expect(result).toBe(t1); - }); - -}); \ No newline at end of file diff --git a/spec/hook_spec.ts b/spec/hook_spec.ts deleted file mode 100644 index e398b53..0000000 --- a/spec/hook_spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - Serialize, - Deserialize, - DeserializeInto, - serialize, - serializeAs, - deserializeAs, - deserialize, - inheritSerialization -} from '../src/serialize'; - -class HookTest { - public hello : string; //not serialized on purpose - public static OnDeserialized(instance : HookTest, json : any) { } - public static OnSerialized(instance : HookTest, json : any) {} -} - -describe("OnDeserialized hooks", function() { - - it("should always call OnDeserialized with Deserialize", function() { - var x : any = {hello: 'Guten Tag'}; - spyOn(HookTest, 'OnDeserialized'); - var inst = Deserialize(x, HookTest); - expect(HookTest.OnDeserialized).toHaveBeenCalledWith(inst, x); - }); - - it("should always call OnDeserialized with DeserializeInto", function() { - var x : any = {hello: 'Guten Tag'}; - spyOn(HookTest, 'OnDeserialized'); - var inst = DeserializeInto(x, HookTest, new HookTest()); - expect(HookTest.OnDeserialized).toHaveBeenCalledWith(inst, x); - }); - - it("should always call OnSerialized with Serialize", function() { - var inst = new HookTest(); - spyOn(HookTest, 'OnSerialized'); - var json = Serialize(inst); - expect(HookTest.OnSerialized).toHaveBeenCalledWith(inst, json); - }); - -}); \ No newline at end of file diff --git a/spec/inherit_serialization_spec.ts b/spec/inherit_serialization_spec.ts deleted file mode 100644 index 405ce27..0000000 --- a/spec/inherit_serialization_spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -/// -import { - __TypeMap, - Serialize, - Deserialize, - serialize, - serializeAs, - deserializeAs, - deserialize, - inheritSerialization -} from '../src/serialize'; - -class T { - @serialize x : number; - @serializeAs('Y') y : number; - @deserialize dX : number; - @deserializeAs('DY') dY : number; -} - -@inheritSerialization(T) -class ExtendedT extends T { - @serialize z : number; - @deserialize dZ : number; -} - -describe('Inherit Serialization', function () { - - it('should inherit serialized properties from a class', function () { - var instance = new ExtendedT(); - instance.x = 1; - instance.y = 2; - instance.z = 3; - var result = Serialize(instance); - expect(result.x).toBe(1); - expect(result.Y).toBe(2); - expect(result.z).toBe(3); - }); - - it('should inherit deserialized properties from a class', function () { - var json = { dX: 1, DY: 2, dZ: 3 }; - var instance = Deserialize(json, ExtendedT); - expect(instance.dX).toBe(1); - expect(instance.dY).toBe(2); - expect(instance.dZ).toBe(3); - }); - -}); \ No newline at end of file diff --git a/spec/key_transform_spec.ts b/spec/key_transform_spec.ts deleted file mode 100644 index 7e6bca4..0000000 --- a/spec/key_transform_spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -/// -import { - __TypeMap, - serialize, - serializeAs, - deserialize, - deserializeAs, - autoserialize, - autoserializeAs, - DeserializeInto, - DeserializeKeysFrom, - SerializeKeysTo, - Serialize, - Deserialize, - SnakeCase, - CamelCase, - UnderscoreCase, - DashCase -} from '../src/serialize'; - -class T1 { - @autoserialize myVar : number; - @autoserializeAs('something-else') other : number; -} - -describe('Key Transforms', function () { - - afterEach(function () { - DeserializeKeysFrom(CamelCase); - SerializeKeysTo(CamelCase); - }); - - it('should just clone key name if no transform functions are set', function() { - SerializeKeysTo(null); - DeserializeKeysFrom(null); - var t1 = new T1(); - t1.myVar = 10; - t1.other = 11; - var result = Serialize(t1); - expect(result['something-else']).toBe(11); - expect(result.myVar).toBe(10); - var result = Deserialize({ - myVar: 10, - 'something-else': 11 - }, T1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - }); - - it('should transform keys if serializedKeyTransform is set', function () { - SerializeKeysTo(UnderscoreCase); - var t1 = new T1(); - t1.myVar = 10; - t1.other = 11; - var result = Serialize(t1); - expect(result['something-else']).toBe(11); - expect(result.my_var).toBe(10); - }); - - it('should transform keys if deserializedKeyTransform is set', function () { - DeserializeKeysFrom(UnderscoreCase); - var result = Deserialize({ - my_var: 10, - 'something-else': 11 - }, T1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - var t1 = new T1(); - result = DeserializeInto({ - my_var: 10, - 'something-else': 11 - }, T1, t1); - expect(result).toBe(t1); - expect(result.myVar).toBe(10); - expect(result.other).toBe(11); - }); - -}); diff --git a/spec/mixed_annotations_spec.ts b/spec/mixed_annotations_spec.ts deleted file mode 100644 index 1b72d65..0000000 --- a/spec/mixed_annotations_spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -/// -import { - __TypeMap, - Serialize, - Deserialize, - serialize, - serializeAs, - deserializeAs, - deserialize -} from '../src/serialize'; - -class T { - @serialize - @deserialize - public x : number; -} - -class T2 { - - @serializeAs('X') - @deserializeAs('_X_') - public x : number; -} - -class T3 { - @serializeAs(T) - @deserializeAs(T2) - public t : any; -} - -describe('Mixed annotations', function() { - it('should create meta data for serialize and deserialize', function() { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedType).toBe(null); - expect(__TypeMap.get(T)[0].deserializedKey).toBe('x'); - }); - - it('can serialize and deserialize with different keys', function() { - var json = {'_X_': 10}; - var instance = new T2(); - instance.x = 20; - var serialized = Serialize(instance); - var deserialized = Deserialize(json, T2); - expect(serialized.X).toBe(20); - expect(serialized.x).toBeUndefined(); - expect(deserialized.x).toBe(10); - expect(deserialized._X_).toBeUndefined(); - }); - - it('can serialize and deserialize with different types', function() { - var json = {t: {'_X_': 10}}; - var instance = new T3(); - instance.t = new T(); - instance.t.x = 20; - var serialized = Serialize(instance); - var deserialized = Deserialize(json, T3); - expect(serialized.t.x).toBe(20); - expect(serialized.x).toBeUndefined(); - expect(deserialized.t instanceof T2).toBe(true); - expect(deserialized.t.x).toBe(10); - }); - -}); - diff --git a/spec/serialize.spec.ts b/spec/serialize.spec.ts new file mode 100644 index 0000000..d106e23 --- /dev/null +++ b/spec/serialize.spec.ts @@ -0,0 +1,847 @@ +import { + autoserializeAs, + autoserializeAsArray, + autoserializeAsJson, + autoserializeAsMap, + autoserializeUsing, + serializeAs, + serializeAsArray, + serializeAsJson, + serializeAsMap, + serializeUsing +} from "../src/annotations"; +import { Serialize, SerializeJSON } from "../src/serialize"; +import { Indexable, JsonObject } from "../src/util"; +import { SetSerializeKeyTransform } from "../src/index"; + +describe("Serializing", function () { + + describe("Unannotated", function () { + + it("will not serialize unannotated fields", function () { + + class Test { + value : number = 1; + } + + const x = new Test(); + const json = Serialize(x, Test); + expect(json).toEqual({}); + + }); + + }); + + describe("SerializeAs", function () { + + function runTests(blockName : string, serializeAs : any, serializeAsMap : any, serializeAsArray : any, serializeAsJson : any) { + + describe(blockName, function () { + + it("serializes basic primitives", function () { + + class Test { + @serializeAs(String) value0 : string; + @serializeAs(Boolean) value1 : boolean; + @serializeAs(Number) value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).toBe("strvalue"); + expect(json["value1"]).toBe(true); + expect(json["value2"]).toBe(100); + + }); + + it("serializes a Date", function () { + class Test { + @serializeAs(Date) value0 : Date; + } + + var d = new Date(); + var s = new Test(); + s.value0 = d; + const json = Serialize(s, Test); + expect(json).toEqual({ + value0: d.toString() + }); + + }); + + it("serializes a RegExp", function () { + class Test { + @serializeAs(RegExp) value0 : RegExp; + } + + var s = new Test(); + s.value0 = /[123]/g; + const json = Serialize(s, Test); + expect(json).toEqual({ + value0: "/[123]/g" + }); + }); + + it("serializes non matching primitive type", function () { + class Test { + @serializeAs(Number) value0 : string; + @serializeAs(String) value1 : boolean; + @serializeAs(Boolean) value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).toBe(null); + expect(json["value1"]).toBe("true"); + expect(json["value2"]).toBe(true); + }); + + it("serializes with different keys", function () { + class Test { + @serializeAs(String, "v0") value0 : string; + @serializeAs(Boolean, "v1") value1 : boolean; + @serializeAs(Number) value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["v0"]).toBe("strvalue"); + expect(json["v1"]).toBe(true); + expect(json["value2"]).toBe(100); + }); + + it("skips undefined keys", function () { + class Test { + @serializeAs(String) value0 : string; + @serializeAs(Boolean) value1 : boolean; + @serializeAs(Number) value2 : number; + } + + var s = new Test(); + s.value0 = void 0; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).not.toBeDefined(); + expect(json["value1"]).toBe(true); + expect(json["value2"]).toBe(100); + }); + + it("does not skip null keys", function () { + class Test { + @serializeAs(String) value0 : string; + @serializeAs(Boolean) value1 : boolean; + @serializeAs(Number) value2 : number; + } + + var s = new Test(); + s.value0 = null; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).toBeNull(); + expect(json["value1"]).toBe(true); + expect(json["value2"]).toBe(100); + }); + + it("serializes nested types", function () { + + class Test { + @serializeAs(String) value0 : string; + @serializeAs(Boolean) value1 : boolean; + @serializeAs(Number) value2 : number; + } + + class Test0 { + @serializeAs(Test) test : Test; + } + + var x = new Test0(); + var s = new Test(); + x.test = s; + s.value0 = null; + s.value1 = true; + s.value2 = 100; + const json = Serialize(x, Test0); + expect(json["test"]).toEqual({ + value0: null, + value1: true, + value2: 100 + }); + }); + + it("serializes doubly nested types", function () { + class Test { + @serializeAs(String) value0 : string; + @serializeAs(Boolean) value1 : boolean; + @serializeAs(Number) value2 : number; + } + + class Test0 { + @serializeAs(Test) test : Test; + } + + class Test1 { + @serializeAs(Test0) test : Test0; + } + + var z = new Test1(); + var x = new Test0(); + var s = new Test(); + x.test = s; + z.test = x; + s.value0 = null; + s.value1 = true; + s.value2 = 100; + const json = Serialize(z, Test1); + expect(json["test"]).toEqual({ + test: { + value0: null, + value1: true, + value2: 100 + } + }); + + }); + + }); + + } + + runTests("Normal", serializeAs, serializeAsMap, serializeAsArray, serializeAsJson); + runTests("Auto", autoserializeAs, autoserializeAsMap, autoserializeAsArray, autoserializeAsJson); + + }); + + describe("SerializeAsMap", function () { + + function runTests(blockName : string, serializeAs : any, serializeAsMap : any, serializeAsArray : any, serializeAsJson : any) { + + describe(blockName, function () { + + it("serializes a map of primitives", function () { + class Test { + @serializeAsMap(Number) values : Indexable; + } + + const t = new Test(); + t.values = { + v0: 1, + v1: 2, + v2: 3 + }; + const json = Serialize(t, Test); + expect(json["values"]).toEqual({ + v0: 1, v1: 2, v2: 3 + }); + }); + + it("serializes a map of typed objects", function () { + class TestType { + @serializeAs(Number) value : number; + + constructor(arg : number) { + this.value = arg; + } + } + + class Test { + @serializeAsMap(TestType) values : Indexable; + } + + const t = new Test(); + t.values = { + v0: new TestType(0), + v1: new TestType(1), + v2: new TestType(2) + }; + const json = Serialize(t, Test); + expect(json["values"]).toEqual({ + v0: { value: 0 }, v1: { value: 1 }, v2: { value: 2 } + }); + }); + + it("serializes a map with a different key name", function () { + class TestType { + @serializeAs(Number) value : number; + + constructor(arg : number) { + this.value = arg; + } + } + + class Test { + @serializeAsMap(TestType, "different") values : Indexable; + } + + const t = new Test(); + t.values = { + v0: new TestType(0), + v1: new TestType(1), + v2: new TestType(2) + }; + const json = Serialize(t, Test); + expect(json["values"]).not.toBeDefined(); + expect(json["different"]).toEqual({ + v0: { value: 0 }, v1: { value: 1 }, v2: { value: 2 } + }); + + }); + + it("serializes nested maps", function () { + class TestType { + @serializeAsMap(Number) value : Indexable; + + constructor(arg : Indexable) { + this.value = arg; + } + } + + class Test { + @serializeAsMap(TestType) values : Indexable; + } + + const t = new Test(); + t.values = { + v0: new TestType({ v00: 1, v01: 2 }), + v1: new TestType({ v10: 2, v11: 2 }), + v2: new TestType({ v20: 3, v21: 2 }) + }; + const json = Serialize(t, Test); + expect(json["values"]).toEqual({ + v0: { value: { v00: 1, v01: 2 } }, + v1: { value: { v10: 2, v11: 2 } }, + v2: { value: { v20: 3, v21: 2 } } + }); + }); + + }); + + it("skips undefined keys", function () { + + class Test { + @serializeAsMap(Number) values : Indexable; + } + + const t = new Test(); + t.values = { + v0: void 0, + v1: 1, + v2: 2 + }; + const json = Serialize(t, Test); + expect(json).toEqual({ + values: { + v1: 1, + v2: 2 + } + }); + + }); + + } + + runTests("Normal", serializeAs, serializeAsMap, serializeAsArray, serializeAsJson); + runTests("Auto", autoserializeAs, autoserializeAsMap, autoserializeAsArray, autoserializeAsJson); + + }); + + describe("SerializeAsArray", function () { + + function runTests(blockName : string, serializeAs : any, serializeAsMap : any, serializeAsArray : any, serializeAsJson : any) { + + describe(blockName, function () { + + it("serializes an array of primitives", function () { + class Test { + @serializeAsArray(Number) value : Array; + } + + const t = new Test(); + t.value = [1, 2, 3]; + const json = Serialize(t, Test); + expect(json["value"]).toEqual([1, 2, 3]); + }); + + it("serializes an array of typed objects", function () { + class TestType { + @serializeAs(String) strVal : string; + + constructor(val : string) { + this.strVal = val; + } + } + + class Test { + @serializeAsArray(TestType) value : Array; + } + + const t = new Test(); + t.value = [ + new TestType("str0"), + new TestType("str1"), + new TestType("str2") + ]; + const json = Serialize(t, Test); + expect(json["value"]).toEqual([ + { strVal: "str0" }, + { strVal: "str1" }, + { strVal: "str2" } + ]); + }); + + it("serializes nested arrays", function () { + class TestTypeL0 { + @serializeAs(String) strVal : string; + + constructor(val : string) { + this.strVal = val; + } + + } + + class TestTypeL1 { + @serializeAsArray(TestTypeL0) l0List : Array; + + constructor(l0List : TestTypeL0[]) { + this.l0List = l0List; + } + + } + + class Test { + @serializeAsArray(TestTypeL1) value : Array; + } + + const t = new Test(); + t.value = [ + new TestTypeL1([new TestTypeL0("00"), new TestTypeL0("01")]), + new TestTypeL1([new TestTypeL0("10"), new TestTypeL0("11")]), + new TestTypeL1([new TestTypeL0("20"), new TestTypeL0("21")]) + ]; + const json = Serialize(t, Test); + expect(json["value"]).toEqual([ + { l0List: [{ strVal: "00" }, { strVal: "01" }] }, + { l0List: [{ strVal: "10" }, { strVal: "11" }] }, + { l0List: [{ strVal: "20" }, { strVal: "21" }] } + ]); + }); + + it("serializes an array with a different key", function () { + class Test { + @serializeAsArray(Number, "different") value : Array; + } + + const t = new Test(); + t.value = [1, 2, 3]; + const json = Serialize(t, Test); + expect(json["value"]).toBeUndefined(); + expect(json["different"]).toEqual([1, 2, 3]); + }); + + }); + + } + + runTests("Normal", serializeAs, serializeAsMap, serializeAsArray, serializeAsJson); + runTests("Auto", autoserializeAs, autoserializeAsMap, autoserializeAsArray, autoserializeAsJson); + + }); + + describe("SerializeJSON", function () { + + function runTests(blockName : string, serializeAs : any, serializeAsMap : any, serializeAsArray : any, serializeAsJson : any) { + + describe(blockName, function () { + + it("serializes a primitive as json", function () { + + class Test { + @serializeAsJson() value0 : string; + @serializeAsJson() value1 : boolean; + @serializeAsJson() value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).toBe("strvalue"); + expect(json["value1"]).toBe(true); + expect(json["value2"]).toBe(100); + }); + + it("serializes an array of primitives as json", function () { + class Test { + @serializeAsJson() value0 : string[]; + @serializeAsJson() value1 : boolean[]; + @serializeAsJson() value2 : number; + } + + var s = new Test(); + s.value0 = ["strvalue", "00"]; + s.value1 = [false, true]; + s.value2 = 100; + const json = Serialize(s, Test); + expect(json["value0"]).toEqual(["strvalue", "00"]); + expect(json["value1"]).toEqual([false, true]); + expect(json["value2"]).toBe(100); + }); + + it("skips undefined keys", function () { + class Test { + @serializeAsJson() value : Indexable; + } + + var s = new Test(); + s.value = { v0: 1, v1: void 0, v2: 2 }; + const json = Serialize(s, Test); + expect(json).toEqual({ + value: { + v0: 1, + v2: 2 + } + }); + }); + + it("serializes an array of non primitives as json", function () { + + class TestL0 { + value0 : string; + value1 : boolean; + value2 : number; + } + + class Test { + @serializeAsJson() values : TestL0[]; + } + + var s = new Test(); + var l0 = new TestL0(); + var l1 = new TestL0(); + s.values = [l0, l1]; + l0.value0 = "strvalue"; + l0.value1 = true; + l0.value2 = 100; + l1.value0 = "strvalue2"; + l1.value1 = true; + l1.value2 = 101; + const json = Serialize(s, Test); + expect(json).toEqual({ + values: [{ + value0: "strvalue", + value1: true, + value2: 100 + }, { + value0: "strvalue2", + value1: true, + value2: 101 + }] + }); + + }); + + it("serializes a map of primitives as json", function () { + + class TestL0 { + value0 : string; + value1 : boolean; + value2 : number; + } + + class Test { + @serializeAsJson() value0 : TestL0; + } + + var s = new Test(); + var l0 = new TestL0(); + s.value0 = l0; + l0.value0 = "strvalue"; + l0.value1 = true; + l0.value2 = 100; + const json = Serialize(s, Test); + expect(json).toEqual({ + value0: { + value0: "strvalue", + value1: true, + value2: 100 + } + }); + + }); + + it("serializes a map of non primitives as json", function () { + + class TestL0 { + value0 : string; + value1 : boolean; + value2 : number; + } + + class Test { + @serializeAsJson() values : Indexable; + } + + var s = new Test(); + var l0 = new TestL0(); + var l1 = new TestL0(); + s.values = { key0: l0, key1: l1 }; + l0.value0 = "strvalue"; + l0.value1 = true; + l0.value2 = 100; + l1.value0 = "strvalue2"; + l1.value1 = true; + l1.value2 = 101; + const json = Serialize(s, Test); + expect(json).toEqual({ + values: { + key0: { + value0: "strvalue", + value1: true, + value2: 100 + }, + key1: { + value0: "strvalue2", + value1: true, + value2: 101 + } + } + }); + + }); + + it("serializes an array of non primitives as json", function () { + + class TestL0 { + value0 : string; + value1 : boolean; + value2 : number; + } + + class Test { + @serializeAsJson() values : TestL0[]; + } + + var s = new Test(); + var l0 = new TestL0(); + var l1 = new TestL0(); + s.values = [l0, l1]; + l0.value0 = "strvalue"; + l0.value1 = true; + l0.value2 = 100; + l1.value0 = "strvalue2"; + l1.value1 = true; + l1.value2 = 101; + const json = Serialize(s, Test); + expect(json).toEqual({ + values: [{ + value0: "strvalue", + value1: true, + value2: 100 + }, { + value0: "strvalue2", + value1: true, + value2: 101 + }] + }); + + }); + + it("does not serialize functions", function () { + class Test { + @serializeAsJson() value0 : () => void; + } + + var s = new Test(); + s.value0 = () => {}; + const json = Serialize(s, Test); + expect(json).toEqual({ + value0: null + }); + }); + + it("serializes json with a different key", function () { + class Test { + @serializeAsJson("different") value0 : string; + } + + var s = new Test(); + s.value0 = "strvalue"; + const json = Serialize(s, Test); + expect(json).toEqual({ + different: "strvalue" + }); + + }); + + it("ignores nested serialization annotations", function () { + class Sub { + @serializeAs(Number) n : string = "100"; + } + + class Test { + @serializeAsJson() value0 : Sub; + } + + var s = new Test(); + s.value0 = new Sub(); + const json = Serialize(s, Test); + expect(json).toEqual({ + value0: { n: "100" } + }); + }); + + it("applies key transforms by default", function () { + SetSerializeKeyTransform(function (value) { + return value.toUpperCase(); + }); + + class Test { + @serializeAsJson() value0 : string; + @serializeAsJson() value1 : boolean; + @serializeAsJson() value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + SetSerializeKeyTransform(null); + expect(json).toEqual({ + VALUE0: "strvalue", + VALUE1: true, + VALUE2: 100 + }); + }); + + it("applies key transforms when set to true", function () { + + SetSerializeKeyTransform(function (value) { + return value.toUpperCase(); + }); + + class Test { + @serializeAsJson(true) value0 : string; + @serializeAsJson(true) value1 : boolean; + @serializeAsJson(true) value2 : number; + } + + var s = new Test(); + s.value0 = "strvalue"; + s.value1 = true; + s.value2 = 100; + const json = Serialize(s, Test); + SetSerializeKeyTransform(null); + expect(json).toEqual({ + VALUE0: "strvalue", + VALUE1: true, + VALUE2: 100 + }); + }); + + it("does not apply key transforms when set to false", function () { + SetSerializeKeyTransform(function (value) { + return value.toUpperCase(); + }); + + class Test { + @serializeAsJson(false) value0 = { v0: "yes", v1: "no" }; + @serializeAsJson(false) value1 : boolean = true; + @serializeAsJson(true) value2 : number = 100; + } + + var s = new Test(); + const json = Serialize(s, Test); + SetSerializeKeyTransform(null); + expect(json).toEqual({ + VALUE0: { v0: "yes", v1: "no" }, + VALUE1: true, + VALUE2: 100 + }); + }); + + }); + } + + runTests("Normal", serializeAs, serializeAsMap, serializeAsArray, serializeAsJson); + runTests("Auto", autoserializeAs, autoserializeAsMap, autoserializeAsArray, autoserializeAsJson); + + }); + + describe("SerializeUsing", function () { + + it("uses the provided function", function () { + function x(value : any) { return "yes"; } + + class Test { + @serializeUsing(x) value : number = 1; + @autoserializeUsing({ Serialize: x, Deserialize: x }) value1 : number = 1; + } + + const s = new Test(); + const json = Serialize(s, Test); + expect(json).toEqual({ + value: "yes", + value1: "yes" + }); + + }); + + }); + + describe("onSerialized", function () { + + it("invokes the handler if provided", function () { + class Test { + + @serializeAs(Number) value : number = 1; + + static onSerialized(json : JsonObject, instance : Test) : void { + json["newvalue"] = "yes"; + expect(instance instanceof Test).toBeTruthy(); + } + + } + + const s = new Test(); + const json = Serialize(s, Test); + expect(json).toEqual({ + value: 1, + newvalue: "yes" + }); + + }); + + it("accepts the return value of onSerialized if provided", function () { + class Test { + + @serializeAs(Number) value : number = 1; + + static onSerialized(json : JsonObject, instance : Test) { + return { v: "hello" }; + } + + } + + const s = new Test(); + const json = Serialize(s, Test); + expect(json).toEqual({ + v: "hello" + }); + + }); + + }); + +}); \ No newline at end of file diff --git a/spec/serialize_annotation_spec.ts b/spec/serialize_annotation_spec.ts deleted file mode 100644 index 8e59c74..0000000 --- a/spec/serialize_annotation_spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -/// -import { __TypeMap, serialize, serializeAs } from '../src/serialize'; - -class T { - @serialize public x : number; -} - -class Vector2 { - @serialize x : number; - @serialize y : number; -} -class AsTest { - @serializeAs(Vector2) v : Vector2; -} - -class AsTest2 { - @serializeAs(Vector2, "VECTOR") v : Vector2; -} - -class AsTest3 { - @serializeAs("z") y : number; -} - -describe('serialize', function () { - it('should create meta data', function() { - expect(__TypeMap.get(T)).toBeDefined(); - expect(__TypeMap.get(T).length).toBe(1); - expect(__TypeMap.get(T)[0].serializedKey).toBe('x'); - expect(__TypeMap.get(T)[0].serializedType).toBe(null); - }); -}); - -describe('serializeAs', function() { - it('should create meta data', function() { - expect(__TypeMap.get(AsTest)).toBeDefined(); - expect(__TypeMap.get(AsTest).length).toBe(1); - expect(__TypeMap.get(AsTest)[0].serializedKey).toBe('v'); - expect(__TypeMap.get(AsTest)[0].serializedType).toBe(Vector2); - }); - - it('should create meta data with a different key', function() { - expect(__TypeMap.get(AsTest3)).toBeDefined(); - expect(__TypeMap.get(AsTest3).length).toBe(1); - expect(__TypeMap.get(AsTest3)[0].serializedKey).toBe('z'); - expect(__TypeMap.get(AsTest3)[0].serializedType).toBe(null); - }); - - it('should create meta data with a different key and type', function() { - expect(__TypeMap.get(AsTest2)).toBeDefined(); - expect(__TypeMap.get(AsTest2).length).toBe(1); - expect(__TypeMap.get(AsTest2)[0].serializedKey).toBe('VECTOR'); - expect(__TypeMap.get(AsTest2)[0].serializedType).toBe(Vector2); - }); -}); - diff --git a/spec/serialize_function_spec.ts b/spec/serialize_function_spec.ts deleted file mode 100644 index 919876a..0000000 --- a/spec/serialize_function_spec.ts +++ /dev/null @@ -1,227 +0,0 @@ -/// -import {__TypeMap, serialize, serializeAs, Serialize, serializeIndexable} from '../src/serialize'; - -class Vector3 { - @serialize x : number; - @serialize y : number; - z : number; - - constructor(x : number, y : number) { - this.x = x; - this.y = y; - this.z = 100; - } -} - -class TArray { - @serialize x : number; - @serialize y : number; - z : number; - - @serializeAs(Vector3) points : Array; - - constructor(x : number, y : number, points : Array) { - this.x = x; - this.y = y; - this.z = 100; - this.points = points; - } -} - -class TSubObject { - @serializeAs(Vector3, 'specialKey') v1 : Vector3; - @serializeAs(Vector3) v2 : Vector3; - - constructor() { - this.v1 = new Vector3(1, 2); - this.v2 = new Vector3(2, 1); - } - - public static OnSerialized(instance : TSubObject, json : any) : void { - //do nothing - } -} - -var SerializeFn = function (src : string) : string { - return 'custom!'; -}; - -var CustomerSerialized = { - Serialize: SerializeFn -}; - -class CustomSerializedTest { - @serializeAs(CustomerSerialized) public x : string; -} - -class CustomSerializedTest2 { - @serializeAs(SerializeFn) public x : string; -} - -describe('Serialize', function () { - it('should serialize a primitive', function () { - expect(Serialize(5)).toBe(5); - expect(Serialize(true)).toBe(true); - expect(Serialize(undefined)).toBe(null); - expect(Serialize(null)).toBe(null); - expect(Serialize("string")).toBe("string"); - }); - - it('should stringify a date', function () { - var d = new Date(); - expect(Serialize(d)).toBe(d.toISOString()); - }); - - it('should stringify a regex', function () { - var reg = /hi/; - expect(Serialize(reg)).toBe(reg.toString()); - }); - - it('should serialize 0', function () { - expect(Serialize(0)).toBe(0); - }); - - it('should serialize false', function () { - expect(Serialize(false)).toBe(false); - }); - - it('should seralize an untyped object', function () { - var obj = { one: 1, yep: true, now: new Date() }; - var serialized = Serialize(obj); - expect(serialized).not.toBe(obj); - expect(serialized.one).toBe(1); - expect(serialized.yep).toBe(true); - expect(serialized.now).toBe(obj.now.toISOString()); - }); - - it('should serialize a nested untyped object', function () { - var obj = { - one: 1, yep: true, now: new Date(), child: { - childOne: 1, childTwo: 2 - } - }; - var serialized = Serialize(obj); - expect(serialized.child.childOne).toBe(1); - expect(serialized.child.childTwo).toBe(2); - }); - - it('should serialize an untyped array', function () { - var array = [{ one: 1 }, { two: 2 }, { three: 3 }]; - var serialized = Serialize(array); - expect(Array.isArray(serialized)).toBe(true); - expect(serialized.length).toBe(3); - expect(serialized[0]).not.toBe(array[0]); - expect(serialized[0].one).toBe(1); - expect(serialized[1]).not.toBe(array[1]); - expect(serialized[1].two).toBe(2); - expect(serialized[2]).not.toBe(array[2]); - expect(serialized[2].three).toBe(3); - }); - - it('should serialize a typed object', function () { - var test = new Vector3(1, 2); - var serialized = Serialize(test); - expect((serialized instanceof Vector3)).toBe(false); - expect(serialized.x).toBe(test.x); - expect(serialized.y).toBe(test.y); - expect(serialized.z).toBe(void 0); - }); - - it('should serialize object with the given type', function () { - var test = {x: 1, y: 2, z: 3}; - var serialized = Serialize(test, Vector3); - expect((serialized instanceof Vector3)).toBe(false); - expect(serialized.x).toBe(test.x); - expect(serialized.y).toBe(test.y); - expect(serialized.z).toBe(void 0); - }); - - it('should serialize a typed object with a typed array', function () { - var test = new TArray(10, 11, [new Vector3(1, 2), new Vector3(2, 1)]); - var serialized = Serialize(test); - expect(serialized.points).toBeDefined(); - expect(Array.isArray(serialized.points)).toBe(true); - expect(serialized.points.length).toBe(2); - expect(serialized.points[0].x).toBe(1); - expect(serialized.points[0].y).toBe(2); - expect(serialized.points[0].z).toBe(void 0); - expect(serialized.points[1].x).toBe(2); - expect(serialized.points[1].y).toBe(1); - expect(serialized.points[1].z).toBe(void 0); - expect(serialized.x).toBe(10); - expect(serialized.y).toBe(11); - expect(Object.keys(serialized).length).toBe(3); - }); - - it('should serialize a typed object with typed subobjects', function () { - var test = new TSubObject(); - var serialized = Serialize(test); - expect(serialized.specialKey).toBeDefined(); - expect(serialized.specialKey.x).toBe(1); - expect(serialized.specialKey.y).toBe(2); - expect(serialized.specialKey.z).toBe(void 0); - expect(serialized.v2).toBeDefined(); - expect(serialized.v2.x).toBe(2); - expect(serialized.v2.y).toBe(1); - expect(serialized.v2.z).toBe(void 0); - }); - - it('will call OnSerialized if a type defines it', function () { - var test = new TSubObject(); - spyOn(TSubObject, 'OnSerialized').and.callThrough(); - var json = Serialize(test); - expect(TSubObject.OnSerialized).toHaveBeenCalledWith(test, json); - }); - - it('should use a custom serializer', function () { - var test = new CustomSerializedTest(); - test.x = 'not custom'; - var result = Serialize(test); - expect(result.x).toBe('custom!'); - }); - - it('should use a custom serialize fn', function () { - var test = new CustomSerializedTest2(); - test.x = 'not custom'; - var result = Serialize(test); - expect(result.x).toBe('custom!'); - }); - - it('should serialize indexable objects', function() { - class Y { - - @serialize thing : string; - - constructor(str : string) { - this.thing = str; - } - - } - class X { - @serializeIndexable(Y) yMap : any; - } - - var x = new X(); - - x.yMap = { - 1: new Y('one'), - 2: new Y('two') - }; - - var json : any = Serialize(x); - expect(json.yMap[1].thing).toBe('one'); - expect(json.yMap[2].thing).toBe('two'); - }); - - // it("should apply custom names recursively", function() { - // class Person { - // @serializeAs(Person, 'Girl_Friend') - // public girlFriend : Person; - // } - // var instance = new Person(); - // instance.girlFriend = new Person(); - // instance.girlFriend.girlFriend = new Person(); - // var json = Serialize(instance, Person); - // }) - -}); \ No newline at end of file diff --git a/spec/typings/jasmine.d.ts b/spec/typings/jasmine.d.ts deleted file mode 100644 index be9637b..0000000 --- a/spec/typings/jasmine.d.ts +++ /dev/null @@ -1,496 +0,0 @@ -// Type definitions for Jasmine 2.2 -// Project: http://jasmine.github.io/ -// Definitions by: Boris Yankov , Theodore Brown , David Pärsson -// Definitions: https://github.com/borisyankov/DefinitelyTyped - - -// For ddescribe / iit use : https://github.com/borisyankov/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts - -declare function describe(description: string, specDefinitions: () => void): void; -declare function fdescribe(description: string, specDefinitions: () => void): void; -declare function xdescribe(description: string, specDefinitions: () => void): void; - -declare function it(expectation: string, assertion?: () => void, timeout?: number): void; -declare function it(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; -declare function fit(expectation: string, assertion?: () => void, timeout?: number): void; -declare function fit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; -declare function xit(expectation: string, assertion?: () => void, timeout?: number): void; -declare function xit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; - -/** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */ -declare function pending(reason?: string): void; - -declare function beforeEach(action: () => void, timeout?: number): void; -declare function beforeEach(action: (done: () => void) => void, timeout?: number): void; -declare function afterEach(action: () => void, timeout?: number): void; -declare function afterEach(action: (done: () => void) => void, timeout?: number): void; - -declare function beforeAll(action: () => void, timeout?: number): void; -declare function beforeAll(action: (done: () => void) => void, timeout?: number): void; -declare function afterAll(action: () => void, timeout?: number): void; -declare function afterAll(action: (done: () => void) => void, timeout?: number): void; - -declare function expect(spy: Function): jasmine.Matchers; -declare function expect(actual: any): jasmine.Matchers; - -declare function fail(e?: any): void; - -declare function spyOn(object: any, method: string): jasmine.Spy; - -declare function runs(asyncMethod: Function): void; -declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void; -declare function waits(timeout?: number): void; - -declare module jasmine { - - var clock: () => Clock; - - function any(aclass: any): Any; - function anything(): Any; - function arrayContaining(sample: any[]): ArrayContaining; - function objectContaining(sample: any): ObjectContaining; - function createSpy(name: string, originalFn?: Function): Spy; - function createSpyObj(baseName: string, methodNames: any[]): any; - function createSpyObj(baseName: string, methodNames: any[]): T; - function pp(value: any): string; - function getEnv(): Env; - function addCustomEqualityTester(equalityTester: CustomEqualityTester): void; - function addMatchers(matchers: CustomMatcherFactories): void; - function stringMatching(str: string): Any; - function stringMatching(str: RegExp): Any; - - interface Any { - - new (expectedClass: any): any; - - jasmineMatches(other: any): boolean; - jasmineToString(): string; - } - - // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() - interface ArrayLike { - length: number; - [n: number]: T; - } - - interface ArrayContaining { - new (sample: any[]): any; - - asymmetricMatch(other: any): boolean; - jasmineToString(): string; - } - - interface ObjectContaining { - new (sample: any): any; - - jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean; - jasmineToString(): string; - } - - interface Block { - - new (env: Env, func: SpecFunction, spec: Spec): any; - - execute(onComplete: () => void): void; - } - - interface WaitsBlock extends Block { - new (env: Env, timeout: number, spec: Spec): any; - } - - interface WaitsForBlock extends Block { - new (env: Env, timeout: number, latchFunction: SpecFunction, message: string, spec: Spec): any; - } - - interface Clock { - install(): void; - uninstall(): void; - /** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */ - tick(ms: number): void; - mockDate(date?: Date): void; - } - - interface CustomEqualityTester { - (first: any, second: any): boolean; - } - - interface CustomMatcher { - compare(actual: T, expected: T): CustomMatcherResult; - compare(actual: any, expected: any): CustomMatcherResult; - } - - interface CustomMatcherFactory { - (util: MatchersUtil, customEqualityTesters: Array): CustomMatcher; - } - - interface CustomMatcherFactories { - [index: string]: CustomMatcherFactory; - } - - interface CustomMatcherResult { - pass: boolean; - message: string; - } - - interface MatchersUtil { - equals(a: any, b: any, customTesters?: Array): boolean; - contains(haystack: ArrayLike | string, needle: any, customTesters?: Array): boolean; - buildFailureMessage(matcherName: string, isNot: boolean, actual: any, ...expected: Array): string; - } - - interface Env { - setTimeout: any; - clearTimeout: void; - setInterval: any; - clearInterval: void; - updateInterval: number; - - currentSpec: Spec; - - matchersClass: Matchers; - - version(): any; - versionString(): string; - nextSpecId(): number; - addReporter(reporter: Reporter): void; - execute(): void; - describe(description: string, specDefinitions: () => void): Suite; - // ddescribe(description: string, specDefinitions: () => void): Suite; Not a part of jasmine. Angular team adds these - beforeEach(beforeEachFunction: () => void): void; - beforeAll(beforeAllFunction: () => void): void; - currentRunner(): Runner; - afterEach(afterEachFunction: () => void): void; - afterAll(afterAllFunction: () => void): void; - xdescribe(desc: string, specDefinitions: () => void): XSuite; - it(description: string, func: () => void): Spec; - // iit(description: string, func: () => void): Spec; Not a part of jasmine. Angular team adds these - xit(desc: string, func: () => void): XSpec; - compareRegExps_(a: RegExp, b: RegExp, mismatchKeys: string[], mismatchValues: string[]): boolean; - compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; - equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; - contains_(haystack: any, needle: any): boolean; - addCustomEqualityTester(equalityTester: CustomEqualityTester): void; - addMatchers(matchers: CustomMatcherFactories): void; - specFilter(spec: Spec): boolean; - } - - interface FakeTimer { - - new (): any; - - reset(): void; - tick(millis: number): void; - runFunctionsWithinRange(oldMillis: number, nowMillis: number): void; - scheduleFunction(timeoutKey: any, funcToCall: () => void, millis: number, recurring: boolean): void; - } - - interface HtmlReporter { - new (): any; - } - - interface HtmlSpecFilter { - new (): any; - } - - interface Result { - type: string; - } - - interface NestedResults extends Result { - description: string; - - totalCount: number; - passedCount: number; - failedCount: number; - - skipped: boolean; - - rollupCounts(result: NestedResults): void; - log(values: any): void; - getItems(): Result[]; - addResult(result: Result): void; - passed(): boolean; - } - - interface MessageResult extends Result { - values: any; - trace: Trace; - } - - interface ExpectationResult extends Result { - matcherName: string; - passed(): boolean; - expected: any; - actual: any; - message: string; - trace: Trace; - } - - interface Trace { - name: string; - message: string; - stack: any; - } - - interface PrettyPrinter { - - new (): any; - - format(value: any): void; - iterateObject(obj: any, fn: (property: string, isGetter: boolean) => void): void; - emitScalar(value: any): void; - emitString(value: string): void; - emitArray(array: any[]): void; - emitObject(obj: any): void; - append(value: any): void; - } - - interface StringPrettyPrinter extends PrettyPrinter { - } - - interface Queue { - - new (env: any): any; - - env: Env; - ensured: boolean[]; - blocks: Block[]; - running: boolean; - index: number; - offset: number; - abort: boolean; - - addBefore(block: Block, ensure?: boolean): void; - add(block: any, ensure?: boolean): void; - insertNext(block: any, ensure?: boolean): void; - start(onComplete?: () => void): void; - isRunning(): boolean; - next_(): void; - results(): NestedResults; - } - - interface Matchers { - - new (env: Env, actual: any, spec: Env, isNot?: boolean): any; - - env: Env; - actual: any; - spec: Env; - isNot?: boolean; - message(): any; - - toBe(expected: any): boolean; - toEqual(expected: any): boolean; - toMatch(expected: any): boolean; - toBeDefined(): boolean; - toBeUndefined(): boolean; - toBeNull(): boolean; - toBeNaN(): boolean; - toBeTruthy(): boolean; - toBeFalsy(): boolean; - toHaveBeenCalled(): boolean; - toHaveBeenCalledWith(...params: any[]): boolean; - toContain(expected: any): boolean; - toBeLessThan(expected: any): boolean; - toBeGreaterThan(expected: any): boolean; - toBeCloseTo(expected: any, precision: any): boolean; - toContainHtml(expected: string): boolean; - toContainText(expected: string): boolean; - toThrow(expected?: any): boolean; - toThrowError(expected?: any, message?: string): boolean; - not: Matchers; - - Any: Any; - } - - interface Reporter { - reportRunnerStarting(runner: Runner): void; - reportRunnerResults(runner: Runner): void; - reportSuiteResults(suite: Suite): void; - reportSpecStarting(spec: Spec): void; - reportSpecResults(spec: Spec): void; - log(str: string): void; - } - - interface MultiReporter extends Reporter { - addReporter(reporter: Reporter): void; - } - - interface Runner { - - new (env: Env): any; - - execute(): void; - beforeEach(beforeEachFunction: SpecFunction): void; - afterEach(afterEachFunction: SpecFunction): void; - beforeAll(beforeAllFunction: SpecFunction): void; - afterAll(afterAllFunction: SpecFunction): void; - finishCallback(): void; - addSuite(suite: Suite): void; - add(block: Block): void; - specs(): Spec[]; - suites(): Suite[]; - topLevelSuites(): Suite[]; - results(): NestedResults; - } - - interface SpecFunction { - (spec?: Spec): void; - } - - interface SuiteOrSpec { - id: number; - env: Env; - description: string; - queue: Queue; - } - - interface Spec extends SuiteOrSpec { - - new (env: Env, suite: Suite, description: string): any; - - suite: Suite; - - afterCallbacks: SpecFunction[]; - spies_: Spy[]; - - results_: NestedResults; - matchersClass: Matchers; - - getFullName(): string; - results(): NestedResults; - log(arguments: any): any; - runs(func: SpecFunction): Spec; - addToQueue(block: Block): void; - addMatcherResult(result: Result): void; - expect(actual: any): any; - waits(timeout: number): Spec; - waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec; - fail(e?: any): void; - getMatchersClass_(): Matchers; - addMatchers(matchersPrototype: CustomMatcherFactories): void; - finishCallback(): void; - finish(onComplete?: () => void): void; - after(doAfter: SpecFunction): void; - execute(onComplete?: () => void): any; - addBeforesAndAftersToQueue(): void; - explodes(): void; - spyOn(obj: any, methodName: string, ignoreMethodDoesntExist: boolean): Spy; - removeAllSpies(): void; - } - - interface XSpec { - id: number; - runs(): void; - } - - interface Suite extends SuiteOrSpec { - - new (env: Env, description: string, specDefinitions: () => void, parentSuite: Suite): any; - - parentSuite: Suite; - - getFullName(): string; - finish(onComplete?: () => void): void; - beforeEach(beforeEachFunction: SpecFunction): void; - afterEach(afterEachFunction: SpecFunction): void; - beforeAll(beforeAllFunction: SpecFunction): void; - afterAll(afterAllFunction: SpecFunction): void; - results(): NestedResults; - add(suiteOrSpec: SuiteOrSpec): void; - specs(): Spec[]; - suites(): Suite[]; - children(): any[]; - execute(onComplete?: () => void): void; - } - - interface XSuite { - execute(): void; - } - - interface Spy { - (...params: any[]): any; - - identity: string; - and: SpyAnd; - calls: Calls; - mostRecentCall: { args: any[]; }; - argsForCall: any[]; - wasCalled: boolean; - } - - interface SpyAnd { - /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */ - callThrough(): Spy; - /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */ - returnValue(val: any): void; - /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */ - callFake(fn: Function): Spy; - /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */ - throwError(msg: string): void; - /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */ - stub(): Spy; - } - - interface Calls { - /** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. **/ - any(): boolean; - /** By chaining the spy with calls.count(), will return the number of times the spy was called **/ - count(): number; - /** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index **/ - argsFor(index: number): any[]; - /** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/ - allArgs(): any[]; - /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/ - all(): CallInfo[]; - /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/ - mostRecent(): CallInfo; - /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/ - first(): CallInfo; - /** By chaining the spy with calls.reset(), will clears all tracking for a spy **/ - reset(): void; - } - - interface CallInfo { - /** The context (the this) for the call */ - object: any; - /** All arguments passed to the call */ - args: any[]; - } - - interface Util { - inherit(childClass: Function, parentClass: Function): any; - formatException(e: any): any; - htmlEscape(str: string): string; - argsToArray(args: any): any; - extend(destination: any, source: any): any; - } - - interface JsApiReporter extends Reporter { - - started: boolean; - finished: boolean; - result: any; - messages: any; - - new (): any; - - suites(): Suite[]; - summarize_(suiteOrSpec: SuiteOrSpec): any; - results(): any; - resultsForSpec(specId: any): any; - log(str: any): any; - resultsForSpecs(specIds: any): any; - summarizeResult_(result: any): any; - } - - interface Jasmine { - Spec: Spec; - clock: Clock; - util: Util; - } - - export var HtmlReporter: HtmlReporter; - export var HtmlSpecFilter: HtmlSpecFilter; - export var DEFAULT_TIMEOUT_INTERVAL: number; -} \ No newline at end of file diff --git a/src/annotations.ts b/src/annotations.ts new file mode 100644 index 0000000..652980e --- /dev/null +++ b/src/annotations.ts @@ -0,0 +1,179 @@ +import {MetaData, MetaDataFlag} from "./meta_data"; +import {IConstructable, isPrimitiveType, SerializableType, SerializeFn, setBitConditionally, ISerializer} from "./util"; + +export function serializeUsing(serializer : SerializeFn, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.serializedKey = (keyName) ? keyName : actualKeyName; + metadata.serializedType = serializer as any; + metadata.flags |= MetaDataFlag.SerializeUsing; + }; +} + +export function serializeAs(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.serializedKey = (keyName) ? keyName : actualKeyName; + metadata.serializedType = type; + metadata.flags |= MetaDataFlag.SerializeObject; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.SerializePrimitive, isPrimitiveType(type)); + }; +} + +export function serializeAsArray(type : SerializableType, keyName? : string) { + return function (target : any, actualKeyName : string) : any { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.serializedKey = (keyName) ? keyName : actualKeyName; + metadata.serializedType = type; + metadata.flags |= MetaDataFlag.SerializeArray; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.SerializePrimitive, isPrimitiveType(type)); + }; +} + +export function serializeAsMap(type : SerializableType, keyName? : string) { + return function (target : any, actualKeyName : string) : any { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.serializedKey = (keyName) ? keyName : actualKeyName; + metadata.serializedType = type; + metadata.flags |= MetaDataFlag.SerializeMap; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.SerializePrimitive, isPrimitiveType(type)); + }; +} + +export function serializeAsJson(keyNameOrTransformKeys? : boolean | string, transformKeys = true) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.serializedKey = (typeof keyNameOrTransformKeys === "string") ? keyNameOrTransformKeys : actualKeyName; + metadata.flags |= (MetaDataFlag.SerializeJSON); + const shouldTransformKeys = typeof keyNameOrTransformKeys === "boolean" ? keyNameOrTransformKeys : transformKeys; + metadata.flags = setBitConditionally( + metadata.flags, + MetaDataFlag.SerializeJSONTransformKeys, + shouldTransformKeys + ); + }; +} + +export function deserializeUsing(serializer : SerializeFn, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.deserializedKey = (keyName) ? keyName : actualKeyName; + metadata.deserializedType = serializer as any; + metadata.flags |= MetaDataFlag.DeserializeUsing; + }; +} + +export function deserializeAs(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.deserializedKey = (keyName) ? keyName : actualKeyName; + metadata.deserializedType = type; + metadata.flags |= MetaDataFlag.DeserializeObject; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.DeserializePrimitive, isPrimitiveType(type)); + }; +} + +export function deserializeAsArray(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.deserializedKey = (keyName) ? keyName : actualKeyName; + metadata.deserializedType = type; + metadata.flags |= MetaDataFlag.DeserializeArray; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.DeserializePrimitive, isPrimitiveType(type)); + }; +} + +export function deserializeAsMap(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.deserializedKey = (keyName) ? keyName : actualKeyName; + metadata.deserializedType = type; + metadata.flags |= MetaDataFlag.DeserializeMap; + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.DeserializePrimitive, isPrimitiveType(type)); + }; +} + +export function deserializeAsJson(keyNameOrTransformKeys? : boolean | string, transformKeys = true) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + metadata.deserializedKey = (typeof keyNameOrTransformKeys === "string") ? keyNameOrTransformKeys : actualKeyName; + metadata.flags |= (MetaDataFlag.DeserializeJSON); + const shouldTransformKeys = typeof keyNameOrTransformKeys === "boolean" ? keyNameOrTransformKeys : transformKeys; + metadata.flags = setBitConditionally( + metadata.flags, + MetaDataFlag.DeserializeJSONTransformKeys, + shouldTransformKeys + ); + }; +} + + +export function autoserializeUsing(serializer : ISerializer, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + const key = (keyName) ? keyName : actualKeyName; + metadata.serializedKey = key; + metadata.deserializedKey = key; + metadata.serializedType = serializer.Serialize as any; + metadata.deserializedType = serializer.Deserialize as any; + metadata.flags |= MetaDataFlag.AutoUsing; + }; +} + +export function autoserializeAs(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + const key = (keyName) ? keyName : actualKeyName; + metadata.deserializedKey = key; + metadata.serializedKey = key; + metadata.deserializedType = type; + metadata.serializedType = type; + metadata.flags |= (MetaDataFlag.SerializeObject | MetaDataFlag.DeserializeObject); + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.AutoPrimitive, isPrimitiveType(type)); + }; +} + +export function autoserializeAsArray(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + const key = (keyName) ? keyName : actualKeyName; + metadata.deserializedKey = key; + metadata.serializedKey = key; + metadata.deserializedType = type; + metadata.serializedType = type; + metadata.flags |= (MetaDataFlag.SerializeArray | MetaDataFlag.DeserializeArray); + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.AutoPrimitive, isPrimitiveType(type)); + }; +} + +export function autoserializeAsMap(type : SerializableType, keyName? : string) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + const key = (keyName) ? keyName : actualKeyName; + metadata.deserializedKey = key; + metadata.serializedKey = key; + metadata.deserializedType = type; + metadata.serializedType = type; + metadata.flags |= (MetaDataFlag.SerializeMap | MetaDataFlag.DeserializeMap); + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.AutoPrimitive, isPrimitiveType(type)); + }; +} + +export function autoserializeAsJson(keyNameOrTransformKeys? : boolean|string, transformKeys = true) { + return function (target : IConstructable, actualKeyName : string) : void { + const metadata = MetaData.getMetaData(target.constructor, actualKeyName); + const key = (typeof keyNameOrTransformKeys === "string") ? keyNameOrTransformKeys : actualKeyName; + const shouldTransformKeys = typeof keyNameOrTransformKeys === "boolean" ? keyNameOrTransformKeys : transformKeys; + metadata.deserializedKey = key; + metadata.serializedKey = key; + metadata.flags |= (MetaDataFlag.SerializeJSON | MetaDataFlag.DeserializeJSON); + metadata.flags = setBitConditionally(metadata.flags, MetaDataFlag.AutoJSONTransformKeys, shouldTransformKeys); + }; +} + +export function inheritSerialization(parentType : IConstructable) { + return function (childType : Function) { + MetaData.inheritMetaData(parentType, childType); + }; +} + diff --git a/src/deserialize.ts b/src/deserialize.ts new file mode 100644 index 0000000..a38cd93 --- /dev/null +++ b/src/deserialize.ts @@ -0,0 +1,210 @@ +import { + getTarget, Indexable, isPrimitiveType, JsonArray, JsonObject, JsonType, SerializablePrimitiveType, + SerializableType, InstantiationMethod +} from "./util"; +import { MetaData, MetaDataFlag } from "./meta_data"; + +function _DeserializeMap(data : JsonObject, type : SerializableType, target? : Indexable, instantiationMethod? : InstantiationMethod) : Indexable { + if (typeof data !== "object") { + throw new Error("Expected input to be of type `object` but received: " + typeof data); + } + + if (target === null || target === void 0) target = {}; + + if (data === null || data === void 0) { + return null; + } + + const keys = Object.keys(data); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = data[key]; + if (value !== void 0) { + target[MetaData.deserializeKeyTransform(key)] = _Deserialize(data[key] as any, type, target[key], instantiationMethod) as T; + } + } + + return target; +} + +export function DeserializeMap(data : JsonObject, type : SerializableType, target? : Indexable, instantiationMethod? : InstantiationMethod) : Indexable { + if (instantiationMethod === void 0) { + instantiationMethod = MetaData.deserializeInstantationMethod; + } + + return _DeserializeMap(data, type, target, instantiationMethod); +} + +function _DeserializeArray(data : JsonArray, type : SerializableType, target? : Array, instantiationMethod? : InstantiationMethod) { + if (!Array.isArray(data)) { + throw new Error("Expected input to be an array but received: " + typeof data); + } + + if (!Array.isArray(target)) target = [] as Array; + + target.length = data.length; + for (let i = 0; i < data.length; i++) { + target[i] = _Deserialize(data[i] as any, type, target[i], instantiationMethod) as T; + } + + return target; +} + +export function DeserializeArray(data : JsonArray, type : SerializableType, target? : Array, instantiationMethod? : InstantiationMethod) { + if (instantiationMethod === void 0) { + instantiationMethod = MetaData.deserializeInstantationMethod; + } + + return _DeserializeArray(data, type, target, instantiationMethod); +} + +function DeserializePrimitive(data : any, type : SerializablePrimitiveType, target? : Date) { + if (type === Date) { + const deserializedDate = new Date(data as string); + if (target instanceof Date) { + target.setTime(deserializedDate.getTime()); + } + else { + return deserializedDate; + } + } + else if (type === RegExp) { + const fragments = data.match(/\/(.*?)\/([gimy])?$/); + return new RegExp(fragments[1], fragments[2] || ""); + } + else if (data === null) { + return null; + } + else { + return (type as any)(data); + } +} + +export function DeserializeJSON(data : JsonType, transformKeys = true, target? : JsonType) : JsonType { + // if (data === null || data === void 0) {} + + if (Array.isArray(data)) { + + if (!Array.isArray(target)) target = new Array(data.length); + + (target as Array).length = data.length; + + for (let i = 0; i < data.length; i++) { + (target as Array)[i] = DeserializeJSON(data[i], transformKeys, (target as Array)[i]); + } + + return target; + } + + const type = typeof data; + + if (type === "object") { + + const retn = (target && typeof target === "object" ? target : {}) as Indexable; + const keys = Object.keys(data as object); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = (data as Indexable)[key]; + if(value !== void 0) { + const retnKey = transformKeys ? MetaData.deserializeKeyTransform(key) : key; + retn[retnKey] = DeserializeJSON((data as Indexable)[key], transformKeys); + } + } + return retn; + + } + else if (type === "function") { + throw new Error("Cannot deserialize a function, input is not a valid json object"); + } + //primitive case + return data; +} + +function _Deserialize(data : JsonObject, type : SerializableType, target? : T, instantiationMethod? : InstantiationMethod) : T | null { + if (data === null) { return null; } + + const metadataList = MetaData.getMetaDataForType(type); + + if (metadataList === null) { + if (typeof type === "function") { + if (isPrimitiveType(type)) { + return DeserializePrimitive(data, type as any, target as any); + } + + switch (instantiationMethod) { + case InstantiationMethod.New: + return new type(); + + case InstantiationMethod.ObjectCreate: + return Object.create(type.prototype); + + default: + return {} as T; + } + } + + return null; + } + + target = getTarget(type as any, target, instantiationMethod) as T; + + for (let i = 0; i < metadataList.length; i++) { + const metadata = metadataList[i]; + + if (metadata.deserializedKey === null) continue; + + const source : any = data[metadata.getDeserializedKey()]; + + if (source === void 0) continue; + + const keyName = metadata.keyName; + const flags = metadata.flags; + + if ((flags & MetaDataFlag.DeserializeMap) !== 0) { + target[keyName] = _DeserializeMap(source, metadata.deserializedType, target[keyName], instantiationMethod); + } + else if ((flags & MetaDataFlag.DeserializeArray) !== 0) { + target[keyName] = _DeserializeArray(source, metadata.deserializedType, target[keyName], instantiationMethod); + } + else if ((flags & MetaDataFlag.DeserializePrimitive) !== 0) { + target[keyName] = DeserializePrimitive(source, metadata.deserializedType as SerializablePrimitiveType, target[keyName]); + } + else if ((flags & MetaDataFlag.DeserializeObject) !== 0) { + target[keyName] = _Deserialize(source, metadata.deserializedType, target[keyName], instantiationMethod); + } + else if ((flags & MetaDataFlag.DeserializeJSON) !== 0) { + target[keyName] = DeserializeJSON(source, (flags & MetaDataFlag.DeserializeJSONTransformKeys) !== 0, instantiationMethod); + } + else if ((flags & MetaDataFlag.DeserializeUsing) !== 0) { + target[keyName] = (metadata.deserializedType as any)(source, target[keyName], instantiationMethod); + } + + } + + if (typeof type.onDeserialized === "function") { + const value = type.onDeserialized(data, target, instantiationMethod); + if (value !== void 0) return value as any; + } + + return target as T; +} + +export function Deserialize(data : JsonObject, type : SerializableType, target? : T, instantiationMethod? : InstantiationMethod) : T | null { + if (instantiationMethod === void 0) { + instantiationMethod = MetaData.deserializeInstantationMethod; + } + + return _Deserialize(data, type, target, instantiationMethod); +} + +export function DeserializeRaw(data : JsonObject, type : SerializableType, target? : T) : T | null { + return _Deserialize(data, type, target, InstantiationMethod.None); +} + +export function DeserializeArrayRaw(data : JsonArray, type : SerializableType, target? : Array) : Array | null { + return _DeserializeArray(data, type, target, InstantiationMethod.None); +} + +export function DeserializeMapRaw(data : Indexable, type : SerializableType, target? : Indexable) : Indexable | null { + return _DeserializeMap(data, type, target, InstantiationMethod.None); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..a8244c0 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,35 @@ +import { MetaData } from "./meta_data"; +import { NoOp } from "./string_transforms"; +import {InstantiationMethod} from "./util"; + +export * from "./serialize"; +export * from "./deserialize"; +export * from "./annotations"; +export * from "./string_transforms"; +export {InstantiationMethod} from './util'; + +export function SetSerializeKeyTransform(fn : (str : string) => string) : void { + if(typeof fn === "function") { + MetaData.serializeKeyTransform = fn; + } + else { + MetaData.serializeKeyTransform = NoOp; + } +} + +export function SetDeserializeKeyTransform(fn : (str : string) => string) : void { + if(typeof fn === "function") { + MetaData.deserializeKeyTransform = fn; + } + else { + MetaData.deserializeKeyTransform = NoOp; + } +} + +export function SetDefaultInstantiationMethod(instantiationMethod : InstantiationMethod) : void { + if (instantiationMethod === null) { + MetaData.deserializeInstantationMethod = InstantiationMethod.New; + } else { + MetaData.deserializeInstantationMethod = instantiationMethod; + } +} diff --git a/src/meta_data.ts b/src/meta_data.ts new file mode 100644 index 0000000..30f9870 --- /dev/null +++ b/src/meta_data.ts @@ -0,0 +1,131 @@ +//helper class to contain serialization meta data for a property, each property +//in a type tagged with a serialization annotation will contain an array of these +//objects each describing one property + +import { IConstructable, SerializableType, InstantiationMethod } from "./util"; +import { NoOp } from "./string_transforms"; + +const TypeMap = new Map>(); + +/** @internal */ +export const enum MetaDataFlag { + DeserializePrimitive = 1 << 1, + SerializePrimitive = 1 << 2, + DeserializeArray = 1 << 3, + SerializeArray = 1 << 4, + DeserializeMap = 1 << 5, + SerializeMap = 1 << 6, + DeserializeJSON = 1 << 7, + SerializeJSON = 1 << 8, + DeserializeJSONTransformKeys = 1 << 9, + SerializeJSONTransformKeys = 1 << 10, + DeserializeUsing = 1 << 11, + SerializeUsing = 1 << 12, + DeserializeObject = 1 << 13, + SerializeObject = 1 << 14, + + AutoPrimitive = SerializePrimitive | DeserializePrimitive, + AutoUsing = SerializeUsing | DeserializeUsing, + AutoJSONTransformKeys = DeserializeJSONTransformKeys | SerializeJSONTransformKeys +} + +/** @internal */ +export class MetaData { + + public keyName : string; //the key name of the property this meta data describes + public serializedKey : string; //the target keyname for serializing + public deserializedKey : string; //the target keyname for deserializing + public serializedType : SerializableType; //the type to use when serializing this property + public deserializedType : SerializableType; //the type to use when deserializing this property + public flags : MetaDataFlag; + + constructor(keyName : string) { + this.keyName = keyName; + this.serializedKey = ""; + this.deserializedKey = ""; + this.deserializedType = Function; + this.serializedType = Function; + this.flags = 0; + } + + public getSerializedKey() : string { + if (this.serializedKey === this.keyName) { + return MetaData.serializeKeyTransform(this.keyName); + } + return this.serializedKey ? this.serializedKey : this.keyName; + } + + public getDeserializedKey() : string { + if (this.deserializedKey === this.keyName) { + return MetaData.deserializeKeyTransform(this.keyName); + } + return MetaData.deserializeKeyTransform(this.deserializedKey ? this.deserializedKey : this.keyName); + } + + //checks for a key name in a meta data array + public static hasKeyName(metadataArray : Array, key : string) : boolean { + for (var i = 0; i < metadataArray.length; i++) { + if (metadataArray[i].keyName === key) return true; + } + return false; + } + + //clone a meta data instance, used for inheriting serialization properties + public static clone(data : MetaData) : MetaData { + const metadata = new MetaData(data.keyName); + metadata.deserializedKey = data.deserializedKey; + metadata.serializedKey = data.serializedKey; + metadata.serializedType = data.serializedType; + metadata.deserializedType = data.deserializedType; + metadata.flags = data.flags; + return metadata; + } + + //gets meta data for a key name, creating a new meta data instance + //if the input array doesn't already define one for the given keyName + public static getMetaData(target : Function, keyName : string) : MetaData { + var metaDataList = TypeMap.get(target); + + if (metaDataList === void 0) { + metaDataList = []; + TypeMap.set(target, metaDataList); + } + + for (var i = 0; i < metaDataList.length; i++) { + if (metaDataList[i].keyName === keyName) { + return metaDataList[i]; + } + } + metaDataList.push(new MetaData(keyName)); + return metaDataList[metaDataList.length - 1]; + + } + + public static inheritMetaData(parentType : IConstructable, childType : IConstructable) { + var parentMetaData : Array = TypeMap.get(parentType) || []; + var childMetaData : Array = TypeMap.get(childType) || []; + for (var i = 0; i < parentMetaData.length; i++) { + const keyName = parentMetaData[i].keyName; + if (!MetaData.hasKeyName(childMetaData, keyName)) { + childMetaData.push(MetaData.clone(parentMetaData[i])); + } + } + TypeMap.set(childType, childMetaData); + } + + public static getMetaDataForType(type : IConstructable) { + if (type !== null && type !== void 0) { + return TypeMap.get(type) || null; + } + return null; + } + + public static readonly TypeMap = TypeMap; + + public static serializeKeyTransform = NoOp; + + public static deserializeKeyTransform = NoOp; + + public static deserializeInstantationMethod = InstantiationMethod.New; + +} \ No newline at end of file diff --git a/src/serialize.ts b/src/serialize.ts index dbd242a..65f5d34 100644 --- a/src/serialize.ts +++ b/src/serialize.ts @@ -1,822 +1,152 @@ -//this library can be used in Node or a browser, make sure our global object points to the right place -declare var global : any; -var win : any = null; -try { - win = window; -} -catch (e) { - win = global; -} -//some other modules might want access to the serialization meta data, expose it here -var TypeMap = win.__CerializeTypeMap = new (win as any).Map(); +import {Indexable, isPrimitiveType, JsonObject, JsonType, SerializablePrimitiveType, SerializableType} from "./util"; +import {MetaData, MetaDataFlag} from "./meta_data"; -//type aliases for serialization functions -export type Serializer = (value : any) => any; -export type Deserializer = (value : any) => any; - -export interface INewable { - new (...args : any[]) : T; -} +export function SerializeMap(source : T, type : SerializableType) : Indexable { + const target : Indexable = {}; + const keys = Object.keys(source); -export interface IEnum { - [enumeration : string] : any -} - -export interface ISerializable { - Serialize? : (value : any) => any; - Deserialize? : (json : any, instance? : any) => any; -} - -//convert strings like my_camel_string to myCamelString -export function CamelCase(str : string) : string { - var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); - return str.replace(STRING_CAMELIZE_REGEXP, function (match, separator, chr) : string { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function (match, separator, chr) : string { - return match.toLowerCase(); - }); -} - -//convert strings like MyCamelString to my_camel_string -export function SnakeCase(str : string) : string { - var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); - return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); -} - -//convert strings like myCamelCase to my_camel_case -export function UnderscoreCase(str : string) : string { - var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); - var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); - return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); -} - -//convert strings like my_camelCase to my-camel-case -export function DashCase(str : string) : string { - var STRING_DASHERIZE_REGEXP = (/([a-z\d])([A-Z])/g); - str = str.replace(/_/g, '-'); - return str.replace(STRING_DASHERIZE_REGEXP, '$1-$2').toLowerCase(); -} - -function deserializeString(value : any) : string|string[] { - if (Array.isArray(value)) { - return value.map(function (element : any) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = (source as any)[key]; + if(value !== void 0) { + target[MetaData.serializeKeyTransform(key)] = Serialize(value, type); + } } -} -function deserializeNumber(value : any) : number|number[] { - if(Array.isArray(value)) { - return value.map(function(element : any) { - return parseFloat(element); - }); - } - else { - return parseFloat(value); - } + return target; } -function deserializeBoolean(value : any) : boolean|boolean[] { - if (Array.isArray(value)) { - return value.map(function (element : any) { - return Boolean(element); - }); - } - else { - return Boolean(value); +export function SerializeArray(source : Array, type : SerializableType) : Array { + const retn = new Array(source.length); + for (let i = 0; i < source.length; i++) { + retn[i] = Serialize(source[i], type); } + return retn; } -function serializeString(value : any) : string|string[] { - if (Array.isArray(value)) { - return value.map(function (element : any) { - return element && element.toString() || null; - }); - } - else { - return value && value.toString() || null; - } -} +export function SerializePrimitive(source : SerializablePrimitiveType, type : SerializablePrimitiveType) : JsonType { -function serializeNumber(value : any) : number|number[] { - if (Array.isArray(value)) { - return value.map(function (element : any) { - return parseInt(element); - }); - } - else { - return parseInt(value); + if (source === null || source === void 0) { + return null; } -} -function serializeBoolean(value : any) : boolean|boolean[] { - if (Array.isArray(value)) { - return value.map(function (element : any) { - return Boolean(element); - }); - } - else { - return Boolean(value); - } -} + if (type === String) return source.toString(); -function getDeserializeFnForType(type : any) : Deserializer { - if (type === String) { - return deserializeString; - } - else if (type === Number) { - return deserializeNumber; - } - else if (type === Boolean) { - return deserializeBoolean; - } - else { - return type; - } -} + if (type === Boolean) return Boolean(source); -function getSerializeFnForType(type : any) : Serializer { - if (type === String) { - return serializeString; - } - else if (type === Number) { - return serializeNumber; - } - else if (type === Boolean) { - return serializeBoolean; + if (type === Number) { + const value = Number(source); + if (isNaN(value)) return null; + return value; } - else { - return type; - } -} -//gets meta data for a key name, creating a new meta data instance -//if the input array doesn't already define one for the given keyName -function getMetaData(array : Array, keyName : string) : MetaData { - for (var i = 0; i < array.length; i++) { - if (array[i].keyName === keyName) { - return array[i]; - } - } - array.push(new MetaData(keyName)); - return array[array.length - 1]; -} + if (type === Date) return source.toString(); -//helper for grabbing the type and keyname from a multi-type input variable -function getTypeAndKeyName(keyNameOrType : string|Function|ISerializable, keyName : string) : {type : Function, key : string} { - var type : Function = null; - var key : string = null; - if (typeof keyNameOrType === "string") { - key = keyNameOrType; + if (type === RegExp) return source.toString(); - } else if (keyNameOrType && typeof keyNameOrType === "function" || typeof keyNameOrType === "object") { - type = keyNameOrType; - key = keyName; - } - return {key: key, type: type}; -} + return source.toString(); -//todo instance.constructor.prototype.__proto__ === parent class, maybe use this? -//because types are stored in a JS Map keyed by constructor, serialization is not inherited by default -//keeping this seperate by default also allows sub classes to serialize differently than their parent -export function inheritSerialization(parentType : Function) : any { - return function (childType : Function) { - var parentMetaData : Array = TypeMap.get(parentType) || []; - var childMetaData : Array = TypeMap.get(childType) || []; - for (var i = 0; i < parentMetaData.length; i++) { - var keyName = parentMetaData[i].keyName; - if (!MetaData.hasKeyName(childMetaData, keyName)) { - childMetaData.push(MetaData.clone(parentMetaData[i])); - } - } - TypeMap.set(childType, childMetaData); - } } -//an untyped serialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the serialization key for that type in the meta data -export function serialize(target : any, keyName : string) : any { - if (!target || !keyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} +export function SerializeJSON(source : any, transformKeys = true) : JsonType { + if (source === null || source === void 0) return null; -//an untyped deserialization property annotation, gets existing meta data for the target or creates -//a new one and assigns the deserialization key for that type in the meta data -export function deserialize(target : any, keyName : string) : any { - if (!target || !keyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} - -//this combines @serialize and @deserialize as defined above -export function autoserialize(target : any, keyName : string) : any { - if (!target || !keyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, keyName); - metadata.serializedKey = keyName; - metadata.deserializedKey = keyName; - TypeMap.set(target.constructor, metaDataList); -} - -//We dont actually need the type to serialize but I like the consistency with deserializeAs which definitely does -//serializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function serializeAs(keyNameOrType : string|Serializer|INewable|ISerializable|IEnum, keyName? : string) : any { - if (!keyNameOrType) return; - var {key, type} = getTypeAndKeyName(keyNameOrType, keyName); - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (key) ? key : actualKeyName; - metadata.serializedType = type; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//Supports serializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function serializeIndexable(type : Serializer|INewable|ISerializable, keyName? : string) : any { - if (!type) return; - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.serializedKey = (keyName) ? keyName : actualKeyName; - metadata.serializedType = type; - metadata.indexable = true; - //this allows the type to be a stand alone function instead of a class - if (type !== Date && type !== RegExp && !TypeMap.get(type) && typeof type === "function") { - metadata.serializedType = { - Serialize: getSerializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function deserializeAs(keyNameOrType : string|Function|INewable|ISerializable|IEnum, keyName? : string) : any { - if (!keyNameOrType) return; - var {key, type} = getTypeAndKeyName(keyNameOrType, keyName); - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - //this allows the type to be a stand alone function instead of a class - //todo maybe add an explicit date and regexp deserialization function here - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//Supports deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function deserializeIndexable(type : Function|INewable|ISerializable, keyName? : string) : any { - if (!type) return; - var key = keyName; - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - metadata.deserializedKey = (key) ? key : actualKeyName; - metadata.deserializedType = type; - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//serializes and deserializes a type using 1.) a custom key name, 2.) a custom type, or 3.) both custom key and type -export function autoserializeAs(keyNameOrType : string|Function|INewable|ISerializable|IEnum, keyName? : string) : any { - if (!keyNameOrType) return; - var {key, type} = getTypeAndKeyName(keyNameOrType, keyName); - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; - } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//Supports serializing/deserializing of dictionary-like map objects, ie: { x: {}, y: {} } -export function autoserializeIndexable(type : Function|INewable|ISerializable, keyName? : string) : any { - if (!type) return; - var key = keyName; - return function (target : any, actualKeyName : string) : any { - if (!target || !actualKeyName) return; - var metaDataList : Array = TypeMap.get(target.constructor) || []; - var metadata = getMetaData(metaDataList, actualKeyName); - var serialKey = (key) ? key : actualKeyName; - metadata.deserializedKey = serialKey; - metadata.deserializedType = type; - metadata.serializedKey = serialKey; - metadata.serializedType = getSerializeFnForType(type); - metadata.indexable = true; - if (!TypeMap.get(type) && type !== Date && type !== RegExp && typeof type === "function") { - metadata.deserializedType = { - Deserialize: getDeserializeFnForType(type) - }; + if (Array.isArray(source)) { + const array = new Array(source.length); + for (let i = 0; i < source.length; i++) { + array[i] = SerializeJSON(source[i], transformKeys); } - TypeMap.set(target.constructor, metaDataList); - }; -} - -//helper class to contain serialization meta data for a property, each property -//in a type tagged with a serialization annotation will contain an array of these -//objects each describing one property -class MetaData { - - public keyName : string; //the key name of the property this meta data describes - public serializedKey : string; //the target keyname for serializing - public deserializedKey : string; //the target keyname for deserializing - public serializedType : Function|INewable|ISerializable; //the type or function to use when serializing this property - public deserializedType : Function|INewable|ISerializable; //the type or function to use when deserializing this property - public indexable : boolean; - - constructor(keyName : string) { - this.keyName = keyName; - this.serializedKey = null; - this.deserializedKey = null; - this.deserializedType = null; - this.serializedType = null; - this.indexable = false; + return array; } - //checks for a key name in a meta data array - public static hasKeyName(metadataArray : Array, key : string) : boolean { - for (var i = 0; i < metadataArray.length; i++) { - if (metadataArray[i].keyName === key) return true; - } - return false; - } + const type = typeof source; - //clone a meta data instance, used for inheriting serialization properties - public static clone(data : MetaData) : MetaData { - var metadata = new MetaData(data.keyName); - metadata.deserializedKey = data.deserializedKey; - metadata.serializedKey = data.serializedKey; - metadata.serializedType = data.serializedType; - metadata.deserializedType = data.deserializedType; - metadata.indexable = data.indexable; - return metadata; - } -} + if (type === "object") { -//merges two primitive objects recursively, overwriting or defining properties on -//`instance` as they defined in `json`. Works on objects, arrays and primitives -function mergePrimitiveObjects(instance : any, json : any) : any { - if (!json) return instance; //if we dont have a json value, just use what the instance defines already - if (!instance) return json; //if we dont have an instance value, just use the json - - //for each key in the input json we need to do a merge into the instance object - Object.keys(json).forEach(function (key : string) { - var transformedKey : string = key; - if (typeof deserializeKeyTransform === "function") { - transformedKey = deserializeKeyTransform(key); - } - var jsonValue : any = json[key]; - var instanceValue : any = instance[key]; - if (Array.isArray(jsonValue)) { - //in the array case we reuse the items that exist already where possible - //so reset the instance array length (or make it an array if it isnt) - //then call mergePrimitiveObjects recursively - instanceValue = Array.isArray(instanceValue) ? instanceValue : []; - instanceValue.length = jsonValue.length; - for (var i = 0; i < instanceValue.length; i++) { - instanceValue[i] = mergePrimitiveObjects(instanceValue[i], jsonValue[i]); - } - } - else if (jsonValue && typeof jsonValue === "object") { - if (!instanceValue || typeof instanceValue !== "object") { - instanceValue = {}; - } - instanceValue = mergePrimitiveObjects(instanceValue, jsonValue); + if (source instanceof Date || source instanceof RegExp) { + return source.toString(); } else { - //primitive case, just use straight assignment - instanceValue = jsonValue; - } - instance[transformedKey] = instanceValue; - }); - return instance; -} - -//takes an array defined in json and deserializes it into an array that ist stuffed with instances of `type`. -//any instances already defined in `arrayInstance` will be re-used where possible to maintain referential integrity. -function deserializeArrayInto(source : Array, type : Function|INewable|ISerializable, arrayInstance : any) : Array { - if (!Array.isArray(arrayInstance)) { - arrayInstance = new Array(source.length); - } - //extend or truncate the target array to match the source array - arrayInstance.length = source.length; - - for (var i = 0; i < source.length; i++) { - arrayInstance[i] = DeserializeInto(source[i], type, arrayInstance[i] || new (type)()); - } - - return arrayInstance; -} - -//takes an object defined in json and deserializes it into a `type` instance or populates / overwrites -//properties on `instance` if it is provided. -function deserializeObjectInto(json : any, type : Function|INewable|ISerializable, instance : any) : any { - var metadataArray : Array = TypeMap.get(type); - //if we dont have an instance we need to create a new `type` - if (instance === null || instance === void 0) { - if (type) { - instance = new (type)(); - } - } - - //if we dont have any meta data and we dont have a type to inflate, just merge the objects - if (instance && !type && !metadataArray) { - return mergePrimitiveObjects(instance, json); - } - - //if we dont have meta data just bail out and keep what we have - if (!metadataArray) { - invokeDeserializeHook(instance, json, type); - return instance; - } - - //for each property in meta data, try to hydrate that property with its corresponding json value - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - //these are not the droids we're looking for (to deserialize), moving along - if (!metadata.deserializedKey) continue; - - var serializedKey = metadata.deserializedKey; - - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - - var source = json[serializedKey]; - - if (source === void 0) continue; - - var keyName = metadata.keyName; - - //if there is a custom deserialize function, use that - if (metadata.deserializedType && typeof (metadata.deserializedType).Deserialize === "function") { - instance[keyName] = (metadata.deserializedType).Deserialize(source); - } - //in the array case check for a type, if we have one deserialize an array full of those, - //otherwise (thanks to @garkin) just do a generic array deserialize - else if (Array.isArray(source)) { - if (metadata.deserializedType) { - instance[keyName] = deserializeArrayInto(source, metadata.deserializedType, instance[keyName]); - } else { - instance[keyName] = deserializeArray(source, null); - } - } - //if the type is a Date, reconstruct a real date instance - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - var deserializedDate = new Date(source); - if (instance[keyName] instanceof Date) { - instance[keyName].setTime(deserializedDate.getTime()); - } - else { - instance[keyName] = deserializedDate; - } - } - //if the type is Regexp, do that - else if (typeof source === "string" && type === RegExp) { - instance[keyName] = new RegExp(source); - } - //if source exists and source is an object type, hydrate that type - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObjectInto(source, metadata.deserializedType, instance[keyName]); - } - else { - instance[keyName] = deserializeObjectInto(source, metadata.deserializedType, instance[keyName]); + const retn : Indexable = {}; + const keys = Object.keys(source); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = source[key]; + if(value !== void 0) { + const retnKey = transformKeys ? MetaData.serializeKeyTransform(key) : key; + retn[retnKey] = SerializeJSON(value, transformKeys); + } } + return retn; } - //primitive case, just copy - else { - instance[keyName] = source; - } - } - - //invoke our after deserialized callback if provided - invokeDeserializeHook(instance, json, type); - - return instance; -} - -//deserializes a bit of json into a `type` -export function Deserialize(json : any, type? : Function|INewable|ISerializable) : any { - - if (Array.isArray(json)) { - return deserializeArray(json, type); - } - else if (json && typeof json === "object") { - return deserializeObject(json, type); - } - else if ((typeof json === "string" || json instanceof Date) && type === Date.prototype.constructor) { - return new Date(json); - } - else if (typeof json === "string" && type === RegExp) { - return new RegExp(json); - } - else { - return json; - } - -} -//takes some json, a type, and a target object and deserializes the json into that object -export function DeserializeInto(source : any, type : Function|INewable|ISerializable, target : any) : any { - if (Array.isArray(source)) { - return deserializeArrayInto(source, type, target || []); } - else if (source && typeof source === "object") { - return deserializeObjectInto(source, type, target || new (type)()); + else if (type === "function") { + return null; } - else { - return target || (type && new (type)()) || null; - } -} -//deserializes an array of json into an array of `type` -function deserializeArray(source : Array, type : Function|INewable|ISerializable) : Array { - var retn : Array = new Array(source.length); - for (var i = 0; i < source.length; i++) { - retn[i] = Deserialize(source[i], type); - } - return retn; + return source; } -function invokeDeserializeHook(instance : any, json : any, type : any) : void { - if (type && typeof(type).OnDeserialized === "function") { - type.OnDeserialized(instance, json); - } -} +export function Serialize(instance : T, type : SerializableType) : JsonObject | null { -function invokeSerializeHook(instance : any, json : any) : void { - if (typeof (instance.constructor).OnSerialized === "function") { - (instance.constructor).OnSerialized(instance, json); + if (instance === void 0 || instance === null) { + return null; } -} -//deserialize a bit of json into an instance of `type` -function deserializeObject(json : any, type : Function|INewable|ISerializable) : any { - var metadataArray : Array = TypeMap.get(type); + const metadataList = MetaData.getMetaDataForType(type); - //if we dont have meta data, just decode the json and use that - if (!metadataArray) { - var inst : any = null; - if (!type) { - inst = JSON.parse(JSON.stringify(json)); + // todo -- maybe move this to a Generic deserialize + if (metadataList === null) { + if (isPrimitiveType(type)) { + return SerializePrimitive(instance as any, type as any) as any; } else { - inst = new (type)(); //todo this probably wrong - invokeDeserializeHook(inst, json, type); + return {}; } - return inst; } - var instance = new (type)(); + const target : Indexable = {}; - //for each tagged property on the source type, try to deserialize it - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; + for (let i = 0; i < metadataList.length; i++) { + const metadata = metadataList[i]; - if (!metadata.deserializedKey) continue; + if (metadata.serializedKey === null) continue; - var serializedKey = metadata.deserializedKey; - - if (metadata.deserializedKey === metadata.keyName) { - if (typeof deserializeKeyTransform === "function") { - serializedKey = deserializeKeyTransform(metadata.keyName); - } - } - - var source = json[serializedKey]; - - var keyName = metadata.keyName; + const source = (instance as any)[metadata.keyName]; if (source === void 0) continue; - if (source === null) { - instance[keyName] = source; - } + const keyName = metadata.getSerializedKey(); + const flags = metadata.flags; - //if there is a custom deserialize function, use that - else if (metadata.deserializedType && typeof (metadata.deserializedType).Deserialize === "function") { - instance[keyName] = (metadata.deserializedType).Deserialize(source); + if ((flags & MetaDataFlag.SerializeMap) !== 0) { + target[keyName] = SerializeMap(source, metadata.serializedType); } - //in the array case check for a type, if we have one deserialize an array full of those, - //otherwise (thanks to @garkin) just do a generic array deserialize - else if (Array.isArray(source)) { - instance[keyName] = deserializeArray(source, metadata.deserializedType || null); + else if ((flags & MetaDataFlag.SerializeArray) !== 0) { + target[keyName] = SerializeArray(source, metadata.serializedType); } - else if ((typeof source === "string" || source instanceof Date) && metadata.deserializedType === Date.prototype.constructor) { - instance[keyName] = new Date(source); + else if ((flags & MetaDataFlag.SerializePrimitive) !== 0) { + target[keyName] = SerializePrimitive(source, metadata.serializedType as SerializablePrimitiveType); } - else if (typeof source === "string" && metadata.deserializedType === RegExp) { - instance[keyName] = new RegExp(json); + else if ((flags & MetaDataFlag.SerializeObject) !== 0) { + target[keyName] = Serialize(source, metadata.serializedType); } - else if (source && typeof source === "object") { - if (metadata.indexable) { - instance[keyName] = deserializeIndexableObject(source, metadata.deserializedType); - } - else { - instance[keyName] = deserializeObject(source, metadata.deserializedType); - } + else if ((flags & MetaDataFlag.SerializeJSON) !== 0) { + target[keyName] = SerializeJSON(source, (flags & MetaDataFlag.SerializeJSONTransformKeys) !== 0); } - else { - instance[keyName] = source; + else if ((flags & MetaDataFlag.SerializeUsing) !== 0) { + target[keyName] = (metadata.serializedType as any)(source); } - } - - invokeDeserializeHook(instance, json, type); - return instance; -} - -function deserializeIndexableObject(source : any, type : Function | ISerializable) : any { - var retn : any = {}; - //todo apply key transformation here? - Object.keys(source).forEach(function (key : string) { - retn[key] = deserializeObject(source[key], type); - }); - return retn; -} - -function deserializeIndexableObjectInto(source : any, type : Function | ISerializable, instance : any) : any { - //todo apply key transformation here? - Object.keys(source).forEach(function (key : string) { - instance[key] = deserializeObjectInto(source[key], type, instance[key]); - }); - return instance; -} - -//take an array and spit out json -function serializeArray(source : Array, type? : Function|ISerializable) : Array { - var serializedArray : Array = new Array(source.length); - for (var j = 0; j < source.length; j++) { - serializedArray[j] = Serialize(source[j], type); } - return serializedArray; -} - -//take an instance of something and try to spit out json for it based on property annotaitons -function serializeTypedObject(instance : any, type? : Function|ISerializable) : any { - - var json : any = {}; - var metadataArray : Array; - if (type) { - metadataArray = TypeMap.get(type); - } else { - metadataArray = TypeMap.get(instance.constructor); - } - - for (var i = 0; i < metadataArray.length; i++) { - var metadata = metadataArray[i]; - - if (!metadata.serializedKey) continue; - - var serializedKey = metadata.serializedKey; - - if (metadata.serializedKey === metadata.keyName) { - if (typeof serializeKeyTransform === "function") { - serializedKey = serializeKeyTransform(metadata.keyName); - } - } - - var source = instance[metadata.keyName]; - - if (source === void 0) continue; - - if (Array.isArray(source)) { - json[serializedKey] = serializeArray(source, metadata.serializedType || null); - } - else if (metadata.serializedType && typeof (metadata.serializedType).Serialize === "function") { - //todo -- serializeIndexableObject probably isn't needed because of how serialize works - json[serializedKey] = (metadata.serializedType).Serialize(source); - - } else { - var value = Serialize(source); - if (value !== void 0) { - json[serializedKey] = value; - } + if (typeof type.onSerialized === "function") { + const value = type.onSerialized(target, instance); + if (value !== void 0) { + return value as JsonObject; } } - invokeSerializeHook(instance, json); - - return json; + return target; } - -//take an instance of something and spit out some json -export function Serialize(instance : any, type? : Function|ISerializable) : any { - if (instance === null || instance === void 0) return null; - - if (Array.isArray(instance)) { - return serializeArray(instance, type); - } - - if (type && TypeMap.has(type)) { - return serializeTypedObject(instance, type); - } - - if (instance.constructor && TypeMap.has(instance.constructor)) { - return serializeTypedObject(instance); - } - - if (instance instanceof Date) { - return instance.toISOString(); - } - - if (instance instanceof RegExp) { - return instance.toString(); - } - - if (instance && typeof instance === 'object' || typeof instance === 'function') { - var keys = Object.keys(instance); - var json : any = {}; - for (var i = 0; i < keys.length; i++) { - //todo this probably needs a key transform - json[keys[i]] = Serialize(instance[keys[i]]); - } - invokeSerializeHook(instance, json); - return json; - } - - return instance; -} - -export function GenericDeserialize(json : any, type : INewable) : T { - return Deserialize(json, type); -} - -export function GenericDeserializeInto(json : any, type : INewable, instance : T) : T { - return DeserializeInto(json, type, instance); -} - -//these are used for transforming keys from one format to another -var serializeKeyTransform : (key : string) => string = null; -var deserializeKeyTransform : (key : string) => string = null; - -//setter for deserializing key transform -export function DeserializeKeysFrom(transform : (key : string) => string) { - deserializeKeyTransform = transform; -} - -//setter for serializing key transform -export function SerializeKeysTo(transform : (key : string) => string) { - serializeKeyTransform = transform; -} - -//this is kinda dumb but typescript doesnt treat enums as a type, but sometimes you still -//want them to be serialized / deserialized, this does the trick but must be called after -//the enum is defined. -export function SerializableEnumeration(e : IEnum) : void { - e.Serialize = function (x : any) : any { - return e[x]; - }; - - e.Deserialize = function (x : any) : any { - return e[x]; - }; -} - -//expose the type map -export {TypeMap as __TypeMap} diff --git a/src/string_transforms.ts b/src/string_transforms.ts new file mode 100644 index 0000000..49a391f --- /dev/null +++ b/src/string_transforms.ts @@ -0,0 +1,36 @@ + +export function NoOp(str : string) : string { + return str; +} + +//regexes +const STRING_CAMELIZE_REGEXP = (/(-|_|\.|\s)+(.)?/g); +const STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); +const STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); +const STRING_UNDERSCORE_REGEXP_2 = (/-|\s+/g); +const STRING_DASHERIZE_REGEXP = (/([a-z\d])([A-Z])/g); + +//convert strings like my_camel_string to myCamelString +export function CamelCase(str : string) : string { + return str.replace(STRING_CAMELIZE_REGEXP, function (match, separator, chr) : string { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function (match, separator, chr) : string { + return match.toLowerCase(); + }); +} + +//convert strings like MyCamelString to my_camel_string +export function SnakeCase(str : string) : string { + return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); +} + +//convert strings like myCamelCase to my_camel_case +export function UnderscoreCase(str : string) : string { + return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); +} + +//convert strings like my_camelCase to my-camel-case +export function DashCase(str : string) : string { + str = str.replace(/_/g, '-'); + return str.replace(STRING_DASHERIZE_REGEXP, '$1-$2').toLowerCase(); +} \ No newline at end of file diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..8caa4b1 --- /dev/null +++ b/src/util.ts @@ -0,0 +1,79 @@ +export type JsonType = null | string | number | boolean | JsonObject | JsonArray; +export type Serializer = (target : T) => JsonType; +export type Deserializer = (data : JsonType, target? : T, instantiationMethod? : InstantiationMethod) => T; +export type IConstructable = { constructor : Function }; +export type SerializeFn = (data : T) => JsonType; +export type SerializablePrimitiveType = + DateConstructor | + NumberConstructor | + BooleanConstructor | + RegExpConstructor | + StringConstructor; + +export enum InstantiationMethod { + None = 0, + New = 1, + ObjectCreate = 2 +} + +export interface JsonObject { + [idx : string] : JsonType|JsonObject; +} + +export interface JsonArray extends Array {} + +export interface ISerializer { + Serialize : Serializer; + Deserialize : Deserializer; +} + +export interface Indexable { + [idx : string] : T; +} + +export interface SerializableType { + new (...args : any[]) : T; + + onSerialized? : (data : JsonObject, instance : T) => JsonObject|void; + onDeserialized? : (data : JsonObject, instance : T, instantiationMethod? : InstantiationMethod) => T|void; +} + + +/** @internal */ +export function getTarget(type : SerializableType, target : T, instantiationMethod : InstantiationMethod) : T { + + if (target !== null && target !== void 0) return target; + + if (type !== null) { + switch (instantiationMethod) { + case InstantiationMethod.New: + return new type(); + + case InstantiationMethod.ObjectCreate: + return Object.create(type.prototype); + } + } + + return {} as T; +} + +/** @internal */ +export function isPrimitiveType(type : Function) : boolean { + return ( + type === String || + type === Boolean || + type === Number || + type === Date || + type === RegExp + ); +} + +/** @internal */ +export function setBitConditionally(value : number, bits : number, condition : boolean) : number { + if (condition) { + return value | bits; + } + else { + return value & ~bits; + } +} diff --git a/tsconfig.json b/tsconfig.json index 27b62a5..baef862 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,12 +4,21 @@ "noImplicitAny": true, "outDir": "./dist/", "preserveConstEnums": false, - "removeComments": false, + "removeComments": true, "target": "es6", - "module": "es6", + "module": "commonjs", "stripInternal": true, + "strictNullChecks": false, "experimentalDecorators": true, "importHelpers": false, - "noImplicitUseStrict": true - } -} \ No newline at end of file + "noEmitHelpers": false, + "declaration": true, + "sourceMap": true, + "moduleResolution": "node" + }, + "exclude": [ + "node_modules", + "spec", + "dist" + ] +}