diff --git a/.gitignore b/.gitignore index d4345031..b13117c6 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ crashlytics.properties crashlytics-build.properties # Created by .ignore support plugin (hsz.mobi) +yarn-error.log \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index e713f3a2..66182de5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,5 @@ language: node_js node_js: - "node" install: - - npm install \ No newline at end of file + - npm install -g yarn + - yarn \ No newline at end of file diff --git a/README.md b/README.md index 3ddd9f33..038b21f3 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,95 @@ -![master build](https://api.travis-ci.org/Volicon/Type-R.svg?branch=master) +![overview](docs/images/overview.png) -# Getting started +# Type-R Overview -Type-R is the modern JS data framework to manage complex domain and UI application state. Features: +Type-R is a serializable type system for JS and TS. Data structures you describe with Type-R models are automatically and with zero effort: -- _It's mapped to JSON by default_. The mapping can handle sophisticated scenarios with nested JSON and relations by id, and can be easily customized for every particular attribute or class. -- _All changes are observable_, happens in the scope of transactions, and there's the fine-grained change events system. -- _Validation_ is performed on the first access to the validation error and never happens twice for unchanged data. -- _Everything is typed at run-time_ and is protected from improper updates. The shape of generated JSON and data classes is guaranteed to match the definitions. -- It still looks like regular JS classes and is freaking fast. Type-R data structures are about 10 times faster than Backbone models and collections. +- mapped to JSON and, optionally, REST API; +- protected from improper updates at run-time; +- deeply observable. -![overview](docs/images/overview.png) +## Features -Data layer is defined as a superposition of three kinds of building blocks: +Mapping of complex JS types to JSON (such as Date, classes, objects trees with cross-references) is automatic with Type-R which eliminates a possibility of programmer's error and improves productivity. Less code to write means less things to unit test, less bugs to fix, and less code to read and understand when making changes. -- *Record* classes with typed attributes. -- Ordered *collections* of records. -- *Stores* are records with a set of collections in its attributes used to resolve id-references in JSON. -- *IOEndpoints* is an entity encapsulating I/O transport which represent the persistent collection of records. +Type-R models safeguard both frontend and backend from errors in JSON. Programmer's mistake on a frontend can't affect the JSON sent to the server. Wrong JSON received from the server will be validated, sanitized, and can't cause catastrophic failures on the frontend. Type-R guarantee that the data structures will retain the declared shape and it immediately reports improper assignments to the console. -Type-R is completely unopinionated on the client-server transport protocol and the view layer technology. It's your perfect M and VM in modern MVVM or MVC architecture. +There are virtually no point in unit-testing Type-R models as they are mostly declarative definitions. They are able to check the structural integrity themselves, and Type-R can be instructed to throw exceptions instead of console logging. It makes the unit tests of the data layer unnecessary, and greately reduces an effort when writing an integration test. -```javascript -import { define, Record } from 'type-r' +## React integration + +Data structures defined with Type-R are deeply observable by default. They can be used to manage the state of React applications right out of box utilizing "unidirectional data flow" with no additional tooling. Type-R data structures support two-way data binding and attribute-level validation rules, making the a complex forms UI a trivial task. Normally, you don't change your UI code to add validation, just add the validation check to model's attributes. + +## Example -// Define email attribute type with encapsulated validation check. -const Email = String.has.check( x => x! || x.indexOf( '@' ) >= 0, 'Invalid email' ); +The main Type-R building block is the `Model` class with attributes types declaration which behaves as a regular JS class. Models and collections of models can be nested indefinitely to define data structures of arbitrary complexity. + +```javascript +import { define, Record, Collection } from '@type-r/models' +import { restfulIO } from '@type-r/endpoints' @define class User extends Record { static attributes = { - name : String.isRequired, // should not be empty for the record to be valid. - email : Email.isRequired + name : '', + email : '' } } @define class Message extends Record { + static endpoint = restfulIO( '/api/messages', { + // REST I/O is simulated when the mock data is present, that's how you start. + mockData : [ { id : 0, createdAt : "1999-07-25T03:33:29.687Z", author : {}, to : [] }] + } ); + static attributes = { - created : Date // = new Date() + createdAt : Date, author : User, // aggregated User record. - to : User.Collection, // aggregating collection of users + to : Collection.of( User ), // aggregated collection of users subject : '', body : '' } } -const msg = new Message(); -assert( !msg.isValid() ); // Is not valid because msg.author has empty attributes +const messages = Collection.of( Message ).create(); -// Listen for the changes in aggregation tree... -msg.on( 'change', () => console.log( 'change!!!' ) ); +await messages.fetch({ params : { page : 0 }}); -msg.transaction( () => { // Prepare to make the sequence of changes on msg - msg.author.name = 'John Dee'; // No 'change' event yet as we're in the transaction. - msg.author.email = 'dee@void.com'; +const msg = messages.first(); +msg.author.name = 'Alan Poe'; +msg.subject = 'Nevermore'; - assert( msg.isValid() ); // Now msg is valid as all of its attributes are valid. -}); // Got single 'change!!!' message in the console. +await msg.save(); ``` -## [Documentation](https://volijs.github.io/Type-R/) +## [API reference and docs](https://volijs.github.io/Type-R/) ## Installation and requirements -Is packed as UMD and ES6 module. No peer dependencies are required. - -`npm install type-r --save-dev` - +Install Type-R models and built-in set of I/O endpoints (restfulIO, localStorageIO, and memoryIO): + +`npm install @type-r/models @type-r/endpoints` + +Install React bindings: + +`npm install @type-r/react` + +Install extended data types (Email, URL, IP, Integer, Microsoft date, UNIX Timestamp date): + +`npm install @type-r/ext-types` + +## Repository structure + +- `models` - Type-R framework core. +- `endpoints` - Type-R endpoints enabling models and collections I/O API. +- `react` - Type-R React bindings. +- `ext-types` - Extended data types. + +- `globals` - `@type-r/globals` providing backward API compatibility for Type-R v2 apps. + +- `mixture` - Events, Mixins, and log router. Used by `@type-r/models`. +- `tests` - private package containing all the unit tests. +- `examples/*` - example `@type-r/react` apps. \ No newline at end of file diff --git a/docs/chapters/releasenotes.md b/ReleaseNotes.md similarity index 68% rename from docs/chapters/releasenotes.md rename to ReleaseNotes.md index 657d6880..827fafd0 100644 --- a/docs/chapters/releasenotes.md +++ b/ReleaseNotes.md @@ -1,6 +1,57 @@ # Release Notes -## 3.0.0 +## v4.0 + +### Overview + +The major goals of this release is to bring the support for writing React applications with React hooks and TypeScript. + +### npm package names changes + +Renamed npm packages: + +- `type-r` -> `@type-r/models` +- `type-r/ext-types` -> `@type-r/ext-types` +- `type-r/globals` -> `@type-r/globals` + +Combined into one package: + +- `type-r/endpoints/*` -> `@type-r/endpoints` + +### `@type-r/models` (former `type-r`) + +The main `type-r` package. + +- More accurate TypeScript typings. +- `Linked` class representing an abstract reference to the value; the foundation of two-way data-binding. +- `model.$.attrName` returns linked attribute used for two-way data binding in React. +- `AttributesMixin` - TypeScript interface to inject attribute types into the Model. Attribute decorators are deprecated and will be removed in v5. + +### `@type-r/react` (new) + +New hooks-based React binding based on `@linked/react`: + +- Local component state management with Type-R: + - `useModel( ModelClass )` + - `useCollection.of( ModelClass )` + - `useCollection.ofRefsTo( ModelClass )` + - `useCollection.subsetOf( collection )` +- `pureRenderProps` - declarative pure render wrapper working with `Date`, `Linked`, type-r models and collections. +- `useChanges( modelOrCollection )` - update React component when global model or collection changes. +- `useLinked( value )` - create linked component state. +- `useIO( async () => { ... } )` - perform an I/O with async functions. + +### `@type-r/endpoints` (former `type-r/endpoints/*`) + +- `modelFetchIO` - read-only endpoint to fetch models. +- `restfulIO` and `modelFetchIO` supports json data mocking. When `mockData` option is present, the HTTP is bypassed and I/O is simulated through the `memoryIO` endpoint. It makes it possible to develop frontend without a test server. +- `restfulIO` and `modelFetchIO` support for templated URLs. + +### `@type-r/mixture` (new) + +Type-R mixins, events, logging router, and helper functions factored out to the separate package. + +## v3.0 ### Breaking changes @@ -10,8 +61,8 @@ Changed semantic which needs to be refactored: -|-|- Typeless attribute | `value(x)` | `type(null).value(x)` Infer type from the value | `x` (except functions) | `value(x)`, or `x` (except functions) -record.parse() override | `record._parse(json)` | no such a method, remove it -record attributes iteration | `record.forEachAttr(obj, iteratee)` | `record.forEach(iteratee)` +model.parse() override | `model._parse(json)` | no such a method, remove it +model attributes iteration | `model.forEachAttr(obj, iteratee)` | `model.forEach(iteratee)` Shared object | `User.shared` | `shared( User )` one-to-many relationship | `RecordClass.from( ref )` | `memberOf( ref )` many-to-many relationship | `CollectionClass.from( ref )` | `subsetOf( ref, CollectionClass? )` @@ -37,7 +88,7 @@ Attribute "Required" check | `Ctor.isRequired` | `type(Ctor).required` - `Infer` infers TypeScript type from the Type-R attribute metatype. - `InferAttrs` infers TypeScript type for the Type-R attributes definitions. -- `attributes({ attrDefs })` returns the properly typed TypeScript Record class. +- `attributes({ attrDefs })` returns the properly typed TypeScript Model class. TypeScript attributes definitions: @@ -57,26 +108,26 @@ Specify type and default value | `@attr(T.value(default)) name : T` | `@type(T). - `Type.from( json, options? )` method to restore object from JSON with a strict type check and validation. ```typescript -@define class User extends Record { +@define class User extends Model { // There's an HTTP REST enpoint for users. static endpoint = restfulIO( '/api/users' ); @auto name : string - // Collection of Role records represented as an array of role.id in JSON. + // Collection of Role models represented as an array of role.id in JSON. // When the "roles" attribute will be accessed for the first time, // User will look-up for a 'roles' attribute of the nearest store to resolve ids to actual Users. @subsetOf( '~roles' ).as roles : Collection } -@define class Role extends Record { +@define class Role extends Model { static endpoint = restfulIO( '/api/roles' ); @auto name : string } -// Store is the regular Record, nothing special. +// Store is the regular Model, nothing special. @define class UsersDirectory extends Store { - // When this record is fetched, fetch all the attributes instead. + // When this model is fetched, fetch all the attributes instead. static endpoint = attributesIO(); // '~roles' references from all aggregated collections @@ -93,15 +144,15 @@ for( let user of directory.users ){ } ``` -## 2.1.0 +## v2.1 This release adds long-awaited HTTP REST endpoint. - IO endpoints moved outside of the man sources tree. Creation of the custom endpoints is easier than ever. - Added HTTP REST endpoint `restfulIO` with relative urls support (https://volicon.github.io/Type-R/#endpoint-restfulio-url-options-). -- Added proxyIO endpoint for creating endpoints from records on the server side (https://volicon.github.io/Type-R/#endpoint-proxyio-recordctor-). +- Added proxyIO endpoint for creating endpoints from models on the server side (https://volicon.github.io/Type-R/#endpoint-proxyio-recordctor-). -## 2.0.0 +## v2.0 This release brings new features which fixes problems with component's inheritance in React bindings and implements long-awaited generic IO implementation based on ES6 promises. @@ -109,12 +160,12 @@ There shouldn't be breaking changes _unless_ you're using custom logger or React ### Generic IO support -New [IOEndpoint]() concept is introduced, making it easy to create IO abstractions. To enable `Record` and `Collection` IO API, you need to assign IO endpoint in the class definition. +New [IOEndpoint]() concept is introduced, making it easy to create IO abstractions. To enable `Model` and `Collection` IO API, you need to assign IO endpoint in the class definition. Endpoint is the class defining CRUD and list operations on JSON data, as well as the methods to subscribe for the data changes. There are two endpoints included with 2.0 release, `memoryIO` which is suitable for mock testing and `localStorageIO` which could be used in demos and prototypes. They can be used as a references as starting points to define your own IO endpoints. ```javascript -@define class User extends Record { +@define class User extends Model { static endpoint = memoryIO(); static attributes = { name : String, @@ -123,7 +174,7 @@ Endpoint is the class defining CRUD and list operations on JSON data, as well as } ``` -There are three Record IO methods (`save()`, `fetch()`, and `destroy()`) and two collection IO method (`fetch()` and `liveUpdates()`) ). All IO methods returns ES6 promises, so you either must have the runtime supporting ES6 or use the ES6 promise polyfill. The promises are modified to be _abortable_ (all of them have `abort()` method). +There are three Model IO methods (`save()`, `fetch()`, and `destroy()`) and two collection IO method (`fetch()` and `liveUpdates()`) ). All IO methods returns ES6 promises, so you either must have the runtime supporting ES6 or use the ES6 promise polyfill. The promises are modified to be _abortable_ (all of them have `abort()` method). ```javascript const user = new User({ name : 'John' }); @@ -215,7 +266,7 @@ In this example, all of the methods defined in the mixin, base class, and subcla ### Other changes -- Update pipeline was rewritten to improve record's initialization speed (collection's fetch speed is improved by 30%). -- Fixed bug causing dynamic type checks to be disabled in records constructors. +- Update pipeline was rewritten to improve model's initialization speed (collection's fetch speed is improved by 30%). +- Fixed bug causing dynamic type checks to be disabled in models constructors. - New implementation of the `Collection.subsetOf` which both fixes some edge case bugs and is more efficient. - New logger handling NODE_ENV variable setting. diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index adf9cd62..00000000 --- a/dist/index.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).Nested={})}(this,function(s){"use strict";function a(t,e){for(var n in e)e.hasOwnProperty(n)&&!t.hasOwnProperty(n)&&(t[n]=e[n]);if(2( dest : T, ...sources : Object[] ) : T\nexport function defaults< T >( dest : T, source : Object ) : T {\n for( var name in source ) {\n if( source.hasOwnProperty( name ) && !dest.hasOwnProperty( name ) ) {\n dest[ name ] = source[ name ];\n }\n }\n\n if( arguments.length > 2 ){\n for( let i = 2; i < arguments.length; i++ ){\n const other = arguments[ i ];\n other && defaults( dest, other );\n }\n }\n\n return dest;\n}\n\n/** Check if value is raw JSON */\nexport function isValidJSON( value : any ) : boolean {\n if( value === null ){\n return true;\n }\n\n switch( typeof value ){\n case 'number' :\n case 'string' :\n case 'boolean' :\n return true;\n\n case 'object':\n var proto = Object.getPrototypeOf( value );\n\n if( proto === Object.prototype || proto === Array.prototype ){\n return every( value, isValidJSON );\n }\n }\n\n return false;\n}\n\n/** Get the base class constructor function.\n * @param Class Subclass constructor function.\n * @returns Base class constructor function.\n */\nexport function getBaseClass( Class : Function ) {\n return Object.getPrototypeOf( Class.prototype ).constructor\n}\n\nexport function assignToClassProto( Class, definition : T, ...names : K[] ) : void {\n for( let name of names ){\n const value = definition[ name ];\n value === void 0 || ( Class.prototype[ name ] = value );\n }\n}\n\n/** Checks whenever given object is an empty hash `{}` */\nexport function isEmpty( obj : {} ) : boolean {\n if( obj ){\n for( let key in obj ){\n if( obj.hasOwnProperty( key ) ){\n return false;\n }\n }\n }\n\n return true;\n}\n\nexport type Iteratee = ( value : any, key? : string | number ) => any;\n\nfunction someArray( arr : any[], fun : Iteratee ) : any {\n let result;\n\n for( let i = 0; i < arr.length; i++ ){\n if( result = fun( arr[ i ], i ) ){\n return result;\n }\n }\n}\n\nfunction someObject( obj : {}, fun : Iteratee ) : any {\n let result;\n\n for( let key in obj ){\n if( obj.hasOwnProperty( key ) ){\n if( result = fun( obj[ key ], key ) ){\n return result;\n }\n }\n }\n}\n\n/** Similar to underscore `_.some` */\nexport function some( obj, fun : Iteratee ) : any {\n if( Object.getPrototypeOf( obj ) === ArrayProto ){\n return someArray( obj, fun );\n }\n else{\n return someObject( obj, fun );\n }\n}\n\n/** Similar to underscore `_.every` */\nexport function every( obj : { }, predicate : Iteratee ) : boolean {\n return !some( obj, x => !predicate( x ) );\n}\n\n/** Similar to `getOwnPropertyDescriptor`, but traverse the whole prototype chain. */\nexport function getPropertyDescriptor( obj : {}, prop : string ) : PropertyDescriptor {\n let desc : PropertyDescriptor;\n\n for( let proto = obj; !desc && proto; proto = Object.getPrototypeOf( proto ) ) {\n desc = Object.getOwnPropertyDescriptor( proto, prop );\n }\n\n return desc;\n}\n\n/** Similar to underscore `_.omit` */\nexport function omit( source : {}, ...rest : string[] ) : {}\nexport function omit( source ) : {} {\n const dest = {}, discard = {};\n\n for( let i = 1; i < arguments.length; i ++ ){\n discard[ arguments[ i ] ] = true;\n }\n\n for( var name in source ) {\n if( !discard.hasOwnProperty( name ) && source.hasOwnProperty( name ) ) {\n dest[ name ] = source[ name ];\n }\n }\n\n return dest;\n}\n\n/** map `source` object properties with a given function, and assign the result to the `dest` object.\n * When `fun` returns `undefined`, skip this value. \n */\nexport function transform< A, B >( dest : { [ key : string ] : A }, source : { [ key : string ] : B }, fun : ( value : B, key : string ) => A | void ) : { [ key : string ] : A } {\n for( var name in source ) {\n if( source.hasOwnProperty( name ) ) {\n var value = fun( source[ name ], name );\n value === void 0 || ( dest[ name ] = < A >value );\n }\n }\n\n return dest;\n}\n\nexport function fastAssign< A >( dest : A, source : {} ) : A {\n for( var name in source ) {\n dest[ name ] = source[ name ];\n }\n\n return dest;\n}\n\nexport function fastDefaults< A >( dest : A, source : {} ) : A {\n for( var name in source ) {\n if( dest[ name ] === void 0 ){\n dest[ name ] = source[ name ];\n }\n }\n\n return dest;\n}\n\n/** Similar to underscore `_.extend` and `Object.assign` */\nexport function assign< T >( dest : T, ...sources : Object[] ) : T\nexport function assign< T >( dest : T, source : Object ) : T {\n for( var name in source ) {\n if( source.hasOwnProperty( name ) ) {\n dest[ name ] = source[ name ];\n }\n }\n\n if( arguments.length > 2 ){\n for( let i = 2; i < arguments.length; i++ ){\n const other = arguments[ i ];\n other && assign( dest, other );\n }\n }\n\n return dest;\n}\n\n/** Similar to underscore `_.keys` */\nexport function keys( o : any ) : string[]{\n return o ? Object.keys( o ) : [];\n}\n\n/** Similar to underscore `_.once` */\nexport function once( func : Function ) : Function {\n var memo, first = true;\n return function() {\n if ( first ) {\n first = false;\n memo = func.apply(this, arguments);\n func = null;\n }\n return memo;\n };\n}\n\nconst ArrayProto = Array.prototype,\n DateProto = Date.prototype,\n ObjectProto = Object.prototype;\n\n/**\n * Determine whenever two values are not equal, deeply traversing \n * arrays and plain JS objects (hashes). Dates are compared by enclosed timestamps, all other\n * values are compared with strict comparison.\n */\nexport function notEqual( a : any, b : any) : boolean {\n if( a === b ) return false;\n\n if( a && b && typeof a == 'object' && typeof b == 'object' ) {\n const protoA = Object.getPrototypeOf( a );\n\n if( protoA !== Object.getPrototypeOf( b ) ) return true;\n\n switch( protoA ){\n case DateProto : return +a !== +b;\n case ArrayProto : return arraysNotEqual( a, b );\n case ObjectProto :\n case null:\n return objectsNotEqual( a, b );\n }\n }\n\n return true;\n}\n\nfunction objectsNotEqual( a, b ) {\n const keysA = Object.keys( a );\n\n if( keysA.length !== Object.keys( b ).length ) return true;\n\n for( let i = 0; i < keysA.length; i++ ) {\n const key = keysA[ i ];\n\n if( !b.hasOwnProperty( key ) || notEqual( a[ key ], b[ key ] ) ) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction arraysNotEqual( a, b ) {\n if( a.length !== b.length ) return true;\n\n for( let i = 0; i < a.length; i++ ) {\n if( notEqual( a[ i ], b[ i ] ) ) return true;\n }\n\n return false;\n}\n\n/**\n * Create an object without Object prototype members except hasOwnProperty.\n * @param obj - optional parameter to populate the hash map from.\n */\nconst HashProto = Object.create( null );\nHashProto.hasOwnProperty = ObjectProto.hasOwnProperty;\n\nexport function hashMap( obj? ){\n const hash = Object.create( HashProto );\n return obj ? assign( hash, obj ) : hash;\n}","import { once as _once } from './tools'\n\n/*******************\n * Prebuilt events map, used for optimized bulk event subscriptions.\n *\n * const events = new EventMap({\n * 'change' : true, // Resend this event from self as it is.\n * 'change:attr' : 'localTargetFunction',\n * 'executedInTargetContext' : function(){ ... }\n * 'executedInNativeContext' : '^props.handler'\n * })\n */\nexport interface EventsDefinition {\n [ events : string ] : Function | string | boolean\n}\n\n\nexport class EventMap {\n handlers : EventDescriptor[] = [];\n\n constructor( map? : EventsDefinition | EventMap ){\n if( map ){\n if( map instanceof EventMap ){\n this.handlers = map.handlers.slice();\n }\n else{\n map && this.addEventsMap( map );\n }\n }\n }\n\n merge( map : EventMap ){\n this.handlers = this.handlers.concat( map.handlers );\n }\n\n addEventsMap( map : EventsDefinition ){\n for( let names in map ){\n this.addEvent( names, map[ names ] )\n }\n }\n\n bubbleEvents( names : string ){\n for( let name of names.split( eventSplitter ) ){\n this.addEvent( name, getBubblingHandler( name ) );\n }\n }\n\n addEvent( names : string, callback : Function | string | boolean ){\n const { handlers } = this;\n\n for( let name of names.split( eventSplitter ) ){\n handlers.push( new EventDescriptor( name, callback ) );\n }\n }\n\n subscribe( target : {}, source : EventSource ){\n for( let event of this.handlers ){\n on( source, event.name, event.callback, target );\n }\n }\n\n unsubscribe( target : {}, source : EventSource ){\n for( let event of this.handlers ){\n off( source, event.name, event.callback, target );\n }\n }\n}\n\nexport class EventDescriptor {\n callback : Function\n\n constructor(\n public name : string,\n callback : Function | string | boolean\n ){\n if( callback === true ){\n this.callback = getBubblingHandler( name );\n }\n else if( typeof callback === 'string' ){\n this.callback =\n function localCallback(){\n const handler = this[ callback ];\n handler && handler.apply( this, arguments );\n };\n }\n else{\n this.callback = callback;\n }\n }\n}\n\nconst _bubblingHandlers = {};\n\nfunction getBubblingHandler( event : string ){\n return _bubblingHandlers[ event ] || (\n _bubblingHandlers[ event ] = function( a?, b?, c?, d?, e? ){\n if( d !== void 0 || e !== void 0 ) trigger5( this, event, a, b, c, d, e );\n if( c !== void 0 ) trigger3( this, event, a, b, c );\n else trigger2( this, event, a, b );\n }\n );\n}\n\nexport interface HandlersByEvent {\n [ name : string ] : EventHandler\n}\n\nexport class EventHandler {\n constructor( public callback : Callback, public context : any, public next = null ){}\n}\n\nfunction listOff( _events : HandlersByEvent, name : string, callback : Callback, context : any ){\n const head = _events[ name ];\n\n let filteredHead, prev;\n\n for( let ev = head; ev; ev = ev.next ){\n // Element must be kept\n if( ( callback && callback !== ev.callback && callback !== ev.callback._callback ) ||\n ( context && context !== ev.context ) ){\n \n prev = ev;\n filteredHead || ( filteredHead = ev );\n }\n // Element must be skipped\n else{\n if( prev ) prev.next = ev.next;\n }\n }\n\n if( head !== filteredHead ) _events[ name ] = filteredHead;\n}\n\nfunction listSend2( head : EventHandler, a, b ){\n for( let ev = head; ev; ev = ev.next ) ev.callback.call( ev.context, a, b );\n}\n\nfunction listSend3( head : EventHandler, a, b, c ){\n for( let ev = head; ev; ev = ev.next ) ev.callback.call( ev.context, a, b, c );\n}\n\nfunction listSend4( head : EventHandler, a, b, c, d ){\n for( let ev = head; ev; ev = ev.next ) ev.callback.call( ev.context, a, b, c, d );\n}\n\nfunction listSend5( head : EventHandler, a, b, c, d, e ){\n for( let ev = head; ev; ev = ev.next ) ev.callback.call( ev.context, a, b, c, d, e );\n}\n\nfunction listSend6( head : EventHandler, a, b, c, d, e, f ){\n for( let ev = head; ev; ev = ev.next ) ev.callback.call( ev.context, a, b, c, d, e, f );\n}\n\nexport interface Callback extends Function {\n _callback? : Function\n}\n\n/** @internal */\nexport function on( source : EventSource, name : string, callback : Callback, context? : any ) : void {\n if( callback ){\n const _events = source._events || ( source._events = Object.create( null ) );\n _events[ name ] = new EventHandler( callback, context, _events[ name ] );\n }\n}\n\n/** @internal */\nexport function once( source : EventSource, name : string, callback : Callback, context? : any ) : void {\n if( callback ){\n const once : Callback = _once( function(){\n off( source, name, once );\n callback.apply(this, arguments);\n });\n\n once._callback = callback;\n on( source, name, once, context );\n }\n}\n\n/** @internal */\nexport function off( source : EventSource, name? : string, callback? : Callback, context? : any ) : void {\n const { _events } = source;\n if( _events ){\n if( callback || context ) {\n if( name ){\n listOff( _events, name, callback, context );\n }\n else{\n for( let name in _events ){\n listOff( _events, name, callback, context );\n }\n }\n }\n else if( name ){\n _events[ name ] = void 0;\n }\n else{\n source._events = void 0;\n }\n }\n}\n\nexport interface EventSource {\n /** @internal */\n _events : HandlersByEvent\n}\n\nconst eventSplitter = /\\s+/;\n\n/** @internal */\nexport function strings( api : ApiEntry, source : EventSource, events : string, callback : Callback, context ){\n if( eventSplitter.test( events ) ){\n const names = events.split( eventSplitter );\n for( let name of names ) api( source, name, callback, context );\n }\n else api( source, events, callback, context );\n}\n\n/** @internal */\nexport type ApiEntry = ( source : EventSource, event : string, callback : Callback, context? : any ) => void\n\n/*********************************\n * Event-triggering API\n */\n\n/** @internal */\nexport function trigger2( self : EventSource, name : string, a, b ) : void {\n const { _events } = self;\n if( _events ){\n const queue = _events[ name ],\n { all } = _events;\n\n listSend2( queue, a, b );\n listSend3( all, name, a, b );\n }\n};\n\n/** @internal */\nexport function trigger3( self : EventSource, name : string, a, b, c ) : void{\n const { _events } = self;\n if( _events ){\n const queue = _events[ name ],\n { all } = _events;\n\n listSend3( queue, a, b, c );\n listSend4( all, name, a, b, c );\n }\n};\n\n/** @internal */\nexport function trigger5( self : EventSource, name : string, a, b, c, d, e ) : void{\n const { _events } = self;\n if( _events ){\n const queue = _events[ name ],\n { all } = _events;\n\n listSend5( queue, a, b, c, d, e );\n listSend6( all, name, a, b, c, d, e );\n }\n};","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation. All rights reserved.\r\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\nthis file except in compliance with the License. You may obtain a copy of the\r\nLicense at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\nMERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\nSee the Apache Version 2.0 License for specific language governing permissions\r\nand limitations under the License.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)\r\n t[p[i]] = s[p[i]];\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n 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;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator], i = 0;\r\n if (m) return m.call(o);\r\n return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n","/*****************************************************************\n * Mixins engine and @define metaprogramming class extensions\n *\n * Vlad Balin & Volicon, (c) 2016-2017\n */\nimport { __extends } from 'tslib';\nimport { assign, defaults, getBaseClass, hashMap, transform } from './tools';\n\nexport interface Subclass< T > extends MixableConstructor {\n new ( ...args ) : T\n prototype : T\n}\n\nexport interface MixableConstructor extends Function{\n __super__? : object;\n mixins? : MixinsState;\n onExtend? : ( BaseClass : Function ) => void;\n onDefine? : ( definition : object, BaseClass : Function ) => void;\n define? : ( definition? : object, statics? : object ) => MixableConstructor;\n extend? : ( definition? : T, statics? : object ) => Subclass;\n}\n\nexport interface MixableDefinition {\n mixins? : Mixin[]\n}\n\n/**\n * Base class, holding metaprogramming class extensions.\n * Supports mixins and Class.define metaprogramming method.\n */\nexport class Mixable {\n static onExtend : ( BaseClass : Function ) => void;\n static onDefine : ( definition : object, BaseClass : Function ) => object; \n static __super__ : object\n static mixins : MixinsState;\n\n /** \n * Must be called after inheritance and before 'define'.\n */\n static define( protoProps : MixableDefinition = {}, staticProps? : object ) : MixableConstructor {\n const BaseClass : MixableConstructor = getBaseClass( this );\n\n // Assign statics.\n staticProps && assign( this, staticProps );\n\n // Extract and apply mixins from the definition.\n const { mixins, ...defineMixin } = protoProps;\n mixins && this.mixins.merge( mixins );\n\n // Unshift definition to the the prototype.\n this.mixins.mergeObject( this.prototype, defineMixin, true );\n\n // Unshift definition from statics to the prototype.\n this.mixins.mergeObject( this.prototype, this.mixins.getStaticDefinitions( BaseClass ), true );\n\n // Call onDefine hook, if it's present.\n this.onDefine && this.onDefine( this.mixins.definitions, BaseClass );\n \n // Apply merge rules to inherited members. No mixins can be added after this point.\n this.mixins.mergeInheritedMembers( BaseClass );\n\n return this;\n }\n\n /** Backbone-compatible extend method to be used in ES5 and for backward compatibility */\n static extend< T extends object>(spec? : T, statics? : {} ) : Subclass< T > {\n let TheSubclass : Subclass< T >;\n\n // 1. Create the subclass (ES5 compatibility shim).\n // If constructor function is given...\n if( spec && spec.hasOwnProperty( 'constructor' ) ){\n // ...we need to manually call internal TypeScript __extend function. Hack! Hack!\n TheSubclass = spec.constructor as any;\n __extends( TheSubclass, this );\n }\n // Otherwise, create the subclall in usual way.\n else{\n TheSubclass = class Subclass extends this {} as any;\n }\n\n predefine( TheSubclass );\n spec && TheSubclass.define( spec, statics );\n\n return TheSubclass;\n }\n}\n\n/** @decorator `@predefine` for forward definitions. Can be used with [[Mixable]] classes only.\n * Forwards the call to the [[Mixable.predefine]];\n */\nexport function predefine( Constructor : MixableConstructor ) : void {\n const BaseClass : MixableConstructor = getBaseClass( Constructor );\n\n // Legacy systems support\n Constructor.__super__ = BaseClass.prototype;\n \n // Initialize mixins structures...\n Constructor.define || MixinsState.get( Mixable ).populate( Constructor );\n\n // Make sure Ctor.mixins are ready before the callback...\n MixinsState.get( Constructor );\n\n // Call extend hook.\n Constructor.onExtend && Constructor.onExtend( BaseClass );\n}\n\n/** @decorator `@define` for metaprogramming magic. Can be used with [[Mixable]] classes only.\n * Forwards the call to [[Mixable.define]].\n */\nexport function define( ClassOrDefinition : Function ) : void;\nexport function define( ClassOrDefinition : object ) : ClassDecorator;\nexport function define( ClassOrDefinition : object | MixableConstructor ){\n // @define class\n if( typeof ClassOrDefinition === 'function' ){\n predefine( ClassOrDefinition );\n ( ClassOrDefinition as MixableConstructor ).define();\n }\n // @define({ prop : val, ... }) class\n else{\n return function( Ctor : MixableConstructor ){\n predefine( Ctor );\n Ctor.define( ClassOrDefinition );\n } as any;\n }\n}\n\nexport function definitions( rules : MixinMergeRules ) : ClassDecorator {\n return ( Class : Function ) => {\n const mixins = MixinsState.get( Class );\n mixins.definitionRules = defaults( hashMap(), rules, mixins.definitionRules );\n }\n}\n\n// Create simple property list decorator\nexport function propertyListDecorator( listName: string ) : PropertyDecorator {\n return function propList(proto, name : string) {\n const list = proto.hasOwnProperty( listName ) ?\n proto[ listName ] : (proto[ listName ] = (proto[ listName ] || []).slice()); \n\n list.push(name);\n }\n}\n\nexport function definitionDecorator( definitionKey, value ){\n return ( proto : object, name : string ) => {\n MixinsState\n .get( proto.constructor )\n .mergeObject( proto, {\n [ definitionKey ] : {\n [ name ] : value\n }\n });\n }\n}\n\nexport class MixinsState {\n mergeRules : MixinMergeRules;\n definitionRules : MixinMergeRules;\n definitions : object = {};\n appliedMixins : Mixin[];\n\n // Return mixins state for the class. Initialize if it's not exist.\n static get( Class ) : MixinsState {\n const { mixins } = Class;\n \n return mixins && Class === mixins.Class ? mixins :\n Class.mixins = new MixinsState( Class );\n }\n\n constructor( public Class : MixableConstructor ){\n const { mixins } = getBaseClass( Class );\n\n this.mergeRules = ( mixins && mixins.mergeRules ) || hashMap();\n this.definitionRules = ( mixins && mixins.definitionRules ) || hashMap();\n this.appliedMixins = ( mixins && mixins.appliedMixins ) || [];\n }\n\n getStaticDefinitions( BaseClass : Function ){\n const definitions = hashMap(),\n { Class } = this;\n\n return transform( definitions, this.definitionRules, ( rule, name ) =>{\n if( BaseClass[ name ] !== Class[ name ]){\n return Class[ name ];\n }\n });\n }\n\n merge( mixins : Mixin[] ){\n const proto = this.Class.prototype,\n { mergeRules } = this;\n\n // Copy applied mixins array as it's going to be updated.\n const appliedMixins = this.appliedMixins = this.appliedMixins.slice();\n\n // Apply mixins in sequence...\n for( let mixin of mixins ) {\n // Mixins array should be flattened.\n if( Array.isArray( mixin ) ) {\n this.merge( mixin );\n }\n // Don't apply mixins twice.\n else if( appliedMixins.indexOf( mixin ) < 0 ){\n appliedMixins.push( mixin );\n\n // For constructors, merge _both_ static and prototype members.\n if( typeof mixin === 'function' ){\n // Merge static members\n this.mergeObject( this.Class, mixin );\n\n // merge definitionRules and mergeRules\n const sourceMixins = ( mixin as any ).mixins;\n if( sourceMixins ){\n this.mergeRules = defaults( hashMap(), this.mergeRules, sourceMixins.mergeRules );\n this.definitionRules = defaults( hashMap(), this.definitionRules, sourceMixins.definitionRules );\n this.appliedMixins = this.appliedMixins.concat( sourceMixins.appliedMixins );\n }\n\n // Prototypes are merged according with rules.\n this.mergeObject( proto, mixin.prototype );\n }\n // Handle plain object mixins.\n else {\n this.mergeObject( proto, mixin );\n }\n }\n }\n }\n\n populate( ...ctors : Function[] ){\n for( let Ctor of ctors ) {\n MixinsState.get( Ctor ).merge([ this.Class ]);\n }\n }\n\n mergeObject( dest : object, source : object, unshift? : boolean ) {\n forEachOwnProp( source, name => {\n const sourceProp = Object.getOwnPropertyDescriptor( source, name );\n let rule : MixinMergeRule;\n\n if( rule = this.definitionRules[ name ] ){\n assignProperty( this.definitions, name, sourceProp, rule, unshift );\n }\n\n if( !rule || rule === mixinRules.protoValue ){\n assignProperty( dest, name, sourceProp, this.mergeRules[ name ], unshift );\n }\n });\n }\n\n mergeInheritedMembers( BaseClass : Function ){\n const { mergeRules, Class } = this;\n\n if( mergeRules ){\n const proto = Class.prototype,\n baseProto = BaseClass.prototype;\n\n for( let name in mergeRules ) {\n const rule = mergeRules[ name ];\n\n if( proto.hasOwnProperty( name ) && name in baseProto ){\n proto[ name ] = resolveRule( proto[ name ], baseProto[ name ], rule );\n }\n }\n }\n }\n}\n\nconst dontMix = {\n function : hashMap({\n length : true,\n prototype : true,\n caller : true,\n arguments : true,\n name : true,\n __super__ : true\n }),\n \n object : hashMap({\n constructor : true\n }) \n}\n\nfunction forEachOwnProp( object : object, fun : ( name : string ) => void ){\n const ignore = dontMix[ typeof object ];\n\n for( let name of Object.getOwnPropertyNames( object ) ) {\n ignore[ name ] || fun( name );\n }\n}\n\nexport interface MixinMergeRules {\n [ name : string ] : MixinMergeRule\n}\n\nexport type MixinMergeRule = ( a : any, b : any ) => any\nexport type Mixin = { [ key : string ] : any } | Function\n\n// @mixins( A, B, ... ) decorator.\nexport interface MixinRulesDecorator {\n ( rules : MixinMergeRules ) : ClassDecorator\n value( a : object, b : object) : object;\n protoValue( a : object, b : object) : object;\n merge( a : object, b : object ) : object;\n pipe( a: Function, b : Function ) : Function;\n defaults( a: Function, b : Function ) : Function;\n classFirst( a: Function, b : Function ) : Function;\n classLast( a: Function, b : Function ) : Function;\n every( a: Function, b : Function ) : Function;\n some( a: Function, b : Function ) : Function;\n}\n\nexport const mixins = ( ...list : Mixin[] ) => (\n ( Class : Function ) => MixinsState.get( Class ).merge( list )\n);\n\n// @mixinRules({ name : rule, ... }) decorator.\nexport const mixinRules = ( ( rules : MixinMergeRules ) => (\n ( Class : Function ) => {\n const mixins = MixinsState.get( Class );\n mixins.mergeRules = defaults( rules, mixins.mergeRules );\n }\n) ) as MixinRulesDecorator;\n\n// Pre-defined mixin merge rules\n\nmixinRules.value = ( a, b ) => a;\n\nmixinRules.protoValue = ( a, b ) => a;\n\n// Recursively merge members\nmixinRules.merge = ( a, b ) => defaults( {}, a, b );\n\n // Execute methods in pipe, with the class method executed last.\nmixinRules.pipe = ( a, b ) => (\n function( x : any ) : any {\n return a.call( this, b.call( this, x ) );\n }\n);\n\n // Assume methods return an object, and merge results with defaults (class method executed first)\nmixinRules.defaults = ( a : Function, b : Function ) => (\n function() : object {\n return defaults( a.apply( this, arguments ), b.apply( this, arguments ) );\n }\n);\n\n// Execute methods in sequence staring with the class method.\nmixinRules.classFirst = ( a : Function, b : Function ) => (\n function() : void {\n a.apply( this, arguments );\n b.apply( this, arguments );\n }\n);\n\n // Execute methods in sequence ending with the class method.\nmixinRules.classLast = ( a : Function, b : Function ) => (\n function() : void {\n b.apply( this, arguments );\n a.apply( this, arguments );\n }\n)\n\n // Execute methods in sequence returning the first falsy result.\nmixinRules.every = ( a : Function, b : Function ) =>(\n function() : any {\n return a.apply( this, arguments ) && b.apply( this, arguments );\n }\n);\n // Execute methods in sequence returning the first truthy result.\nmixinRules.some = ( a : Function, b : Function ) =>(\n function() : any {\n return a.apply( this, arguments ) || b.apply( this, arguments );\n }\n);\n\n/**\n * Helpers\n */\n\nfunction assignProperty( dest : object, name : string, sourceProp : PropertyDescriptor, rule : MixinMergeRule, unshift? : boolean ){\n// Destination prop is defined, thus the merge rules must be applied.\n if( dest.hasOwnProperty( name ) ){\n const destProp = Object.getOwnPropertyDescriptor( dest, name );\n\n if( destProp.configurable && 'value' in destProp ){\n dest[ name ] = unshift ?\n resolveRule( sourceProp.value, destProp.value, rule ) :\n resolveRule( destProp.value, sourceProp.value, rule ) ;\n }\n }\n // If destination is empty, just copy the prop over.\n else{\n Object.defineProperty( dest, name, sourceProp );\n }\n}\n\nfunction resolveRule( dest, source, rule : MixinMergeRule ){\n // When destination is empty, take the source.\n if( dest === void 0 ) return source;\n\n // In these cases we take non-empty destination:\n if( !rule || source === void 0 ) return dest;\n\n // In other cases we must merge values.\n return rule( dest, source );\n}","import * as _eventsApi from './eventsource';\nimport { EventMap, EventsDefinition, EventSource, HandlersByEvent } from './eventsource';\nimport { define, definitions, Mixable, MixableConstructor, mixinRules, MixinsState } from './mixins';\nimport { omit, transform } from './tools';\n\nconst { strings, on, off, once, trigger5, trigger2, trigger3 } = _eventsApi;\n\nlet _idCount = 0;\n\nfunction uniqueId() : string {\n return 'l' + _idCount++;\n}\n\nexport { EventMap, EventsDefinition };\n\nexport interface MessengerDefinition {\n _localEvents? : EventMap\n localEvents? : EventsDefinition\n properties? : PropertyMap\n [ name : string ] : any\n}\n\nexport interface PropertyMap {\n [ name : string ] : Property\n}\n\nexport type Property = PropertyDescriptor | ( () => any )\n\nexport interface MessengersByCid {\n [ cid : string ] : Messenger\n}\n\nexport type EventCallbacks = { [ events : string ] : EventCallback }\nexport type EventCallback = ( this : Context, ...args : any[] ) => void\n\n/*************************\n * Messenger is mixable class with capabilities of sending and receiving synchronous events.\n * This class itself can serve as both mixin and base class.\n */\n\n@define\n@definitions({\n properties : mixinRules.merge,\n localEvents : mixinRules.merge\n})\nexport class Messenger implements Mixable, EventSource {\n // Define extendable mixin static properties.\n /** @internal */\n static __super__ : object;\n static mixins : MixinsState;\n static onExtend : ( BaseClass : Function ) => void;\n static define : ( definition? : MessengerDefinition, statics? : object ) => MixableConstructor;\n static extend : ( definition? : MessengerDefinition, statics? : object ) => MixableConstructor;\n static onDefine({ localEvents, _localEvents, properties } : MessengerDefinition, BaseClass? : typeof Mixable ){\n // Handle localEvents definition\n if( localEvents || _localEvents ){\n const eventsMap = new EventMap( this.prototype._localEvents );\n\n localEvents && eventsMap.addEventsMap( localEvents );\n _localEvents && eventsMap.merge( _localEvents );\n \n this.prototype._localEvents = eventsMap;\n }\n\n // Handle properties definitions...\n if( properties ){\n Object.defineProperties( this.prototype, transform( {}, properties, toPropertyDescriptor ) );\n }\n }\n\n /** @internal */ \n _events : HandlersByEvent = void 0;\n\n /** @internal */ \n _listeningTo : MessengersByCid = void 0\n\n /** Unique client-only id. */\n cid : string\n\n /** @internal Prototype-only property to manage automatic local events subscription */ \n _localEvents : EventMap\n\n constructor(){\n this.cid = uniqueId();\n this.initialize.apply( this, arguments );\n\n // TODO: local events subscribe?\n }\n\n /** Method is called at the end of the constructor */\n initialize() : void {}\n \n on( events : string | EventCallbacks, callback?, context? ) : this {\n if( typeof events === 'string' ) strings( on, this, events, callback, context );\n else for( let name in events ) strings( on, this, name, events[ name ], context || callback );\n\n return this;\n }\n\n once( events : string | EventCallbacks, callback?, context? ) : this {\n if( typeof events === 'string' ) strings( once, this, events, callback, context );\n else for( let name in events ) strings( once, this, name, events[ name ], context || callback );\n\n return this;\n }\n\n off( events? : string | EventCallbacks, callback?, context? ) : this {\n if( !events ) off( this, void 0, callback, context );\n else if( typeof events === 'string' ) strings( off, this, events, callback, context );\n else for( let name in events ) strings( off, this, name, events[ name ], context || callback );\n\n return this;\n }\n\n // Trigger one or many events, firing all bound callbacks. Callbacks are\n // passed the same arguments as `trigger` is, apart from the event name\n // (unless you're listening on `\"all\"`, which will cause your callback to\n // receive the true name of the event as the first argument).\n trigger(name : string, a?, b?, c?, d?, e? ) : this {\n if( d !== void 0 || e !== void 0 ) trigger5( this, name, a, b, c, d, e );\n else if( c !== void 0 ) trigger3( this, name, a, b, c );\n else trigger2( this, name, a, b );\n return this;\n }\n\n listenTo( source : Messenger, a : string | EventCallbacks, b? : Function ) : this {\n if( source ){\n addReference( this, source );\n source.on( a, !b && typeof a === 'object' ? this : b, this );\n }\n\n return this;\n }\n\n listenToOnce( source : Messenger, a : string | EventCallbacks, b? : Function ) : this {\n if( source ){\n addReference( this, source );\n source.once( a, !b && typeof a === 'object' ? this : b, this );\n }\n\n return this;\n }\n\n stopListening( a_source? : Messenger, a? : string | EventCallbacks, b? : Function ) : this {\n const { _listeningTo } = this;\n if( _listeningTo ){\n const removeAll = !( a || b ),\n second = !b && typeof a === 'object' ? this : b;\n\n if( a_source ){\n const source = _listeningTo[ a_source.cid ];\n if( source ){\n if( removeAll ) delete _listeningTo[ a_source.cid ];\n source.off( a, second, this );\n }\n }\n else if( a_source == null ){\n for( let cid in _listeningTo ) _listeningTo[ cid ].off( a, second, this );\n\n if( removeAll ) ( this._listeningTo = void 0 );\n }\n }\n\n return this;\n }\n\n /**\n * Destructor. Stops messenger from listening to all objects,\n * and stop others from listening to the messenger. \n */\n _disposed : boolean\n\n dispose() : void {\n if( this._disposed ) return;\n\n this.stopListening();\n this.off();\n\n this._disposed = true;\n }\n}\n\n/**\n * Backbone 1.2 API conformant Events mixin.\n */\nexport const Events : Messenger = omit( Messenger.prototype, 'constructor', 'initialize' );\n\n/**\n * Messenger Private Helpers \n */\n\nfunction toPropertyDescriptor( x : Property ) : PropertyDescriptor {\n if( x ){\n return typeof x === 'function' ? { get : < () => any >x, configurable : true } : x;\n }\n}\n\nfunction addReference( listener : Messenger, source : Messenger ){\n const listeningTo = listener._listeningTo || (listener._listeningTo = Object.create( null ) ),\n cid = source.cid || ( source.cid = uniqueId() );\n\n listeningTo[ cid ] = source;\n}","import { Messenger } from './events'\nimport { define } from './mixins';\n\nexport type LogLevel = 'error' | 'warn' | 'debug' | 'info' | 'log';\nexport type LoggerEventHandler = ( topic : string, msg : string, props : object ) => void;\n\nexport const isProduction = typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production',\n logEvents : LogLevel[] = isProduction ?\n [ 'error', 'info' ] :\n [ 'error', 'warn', 'debug', 'info', 'log' ];\n\n@define\nexport class Logger extends Messenger {\n counter : { [ level in LogLevel ]? : number } = {}\n\n // Log events of the given log level to the console, optionally filtered by topic\n logToConsole( level : LogLevel, filter? : RegExp ) : this {\n return this.on( level, ( topic, msg, props ) => {\n if( !filter || filter.test( topic ) ){\n const args = [ `[${topic}] ${msg}` ];\n \n for( let name in props ){\n args.push( `\\n\\t${name}:`, toString( props[ name ] ) );\n }\n \n console[ level ].apply( console, args );\n }\n });\n }\n\n // Fire exception on the events of the given log level, optionally filtered by topic\n throwOn( level : LogLevel, filter? : RegExp ) : this {\n return this.on( level, ( topic, msg, props ) => {\n if( !filter || filter.test( topic ) ){\n throw new Error( `[${topic}] ${msg}` );\n }\n });\n }\n\n // Count log events of the given level, optionally filtered by topic\n count( level : LogLevel, filter? : RegExp ) : this {\n return this.on( level, ( topic, msg, props ) => {\n if( !filter || filter.test( topic ) ){\n this.counter[ level ] = ( this.counter[ level ] || 0 ) + 1;\n }\n });\n }\n\n trigger : ( level : LogLevel, topic : string, message : string, props? : object ) => this;\n \n off : ( event? : LogLevel ) => this;\n\n\n on( handlers : { [ name in LogLevel ] : LoggerEventHandler } ) : this;\n on( handlers : LogLevel, handler : LoggerEventHandler ) : this;\n on( handlers : 'all', handler : ( level : LogLevel, topic : string, msg : string, props : object ) => void ) : this;\n on( a : any, b? : any ){\n return super.on( a, b );\n }\n}\n\n/**\n * Convert objects to the plain text friendly format.\n * primitives as in JSON.\n */\nlet toString = typeof window === 'undefined' ? \n something => {\n if( something && typeof something === 'object' ){\n const { __inner_state__ } = something,\n value = __inner_state__ || something,\n isArray = Array.isArray( value );\n\n const body = isArray ? `[ length = ${ value.length } ]` : `{ ${ Object.keys( value ).join( ', ' )} }`;\n\n return something.constructor.name + ' ' + body;\n }\n\n return JSON.stringify( something );\n }\n : x => x;\n\nexport const logger = new Logger();\n\nif( typeof console !== 'undefined' ) {\n for( let event of logEvents ){\n logger.logToConsole( event );\n }\n}\n\nexport const throwingLogger = new Logger();\nthrowingLogger.throwOn( 'error' ).throwOn( 'warn' );\n\nexport const log : typeof logger.trigger = logger.trigger.bind( logger );","export interface IONode {\n /** @internal */\n _endpoint : IOEndpoint\n\n /** @internal */\n _ioPromise : IOPromise< this >\n}\n\nexport interface IOPromise extends Promise {\n abort? : () => void\n}\n\nexport interface IOEndpoint {\n list( options : IOOptions, collection? ) : IOPromise\n create( json : any, options : IOOptions, record? ) : IOPromise\n update( id : string | number, json :any, options : IOOptions, record? ) : IOPromise\n read( id : string | number, options : IOOptions, record? ) : IOPromise\n destroy( id : string | number, options : IOOptions, record? ) : IOPromise\n subscribe( events : IOEvents, collection? ) : IOPromise\n unsubscribe( events : IOEvents, collection? ) : void\n}\n\nexport interface IOOptions {\n ioMethod? : 'save' | 'fetch'\n}\n\nexport interface IOEvents {\n updated? : ( json : any ) => void\n removed? : ( json : any ) => void\n}\n\nexport function getOwnerEndpoint( self ) : IOEndpoint {\n // Check if we are the member of the collection...\n const { collection } = self;\n if( collection ){\n return getOwnerEndpoint( collection );\n }\n\n // Now, if we're the member of the model...\n if( self._owner ){\n const { _endpoints } = self._owner;\n return _endpoints && _endpoints[ self._ownerKey ];\n }\n}\n\n/**\n * Create abortable promise.\n * Adds `promise.abort()` function which rejects the promise by default\n * initialize() function takes third optional argument `abort : ( resolve, reject ) => void`,\n * which can be used to add custom abort handling.\n */\ndeclare var Promise: PromiseConstructorLike;\n\nexport function createIOPromise( initialize : InitIOPromise ) : IOPromise{\n let resolve, reject, onAbort;\n\n function abort( fn ){\n onAbort = fn;\n }\n\n const promise : IOPromise = new Promise( ( a_resolve, a_reject ) =>{\n reject = a_reject;\n resolve = a_resolve;\n initialize( resolve, reject, abort );\n }) as IOPromise;\n\n promise.abort = () => {\n onAbort ? onAbort( resolve, reject ) : reject( new Error( \"I/O Aborted\" ) );\n }\n\n return promise;\n}\n\nexport type InitIOPromise = ( resolve : ( x? : any ) => void, reject : ( x? : any ) => void, abort? : ( fn : Function ) => void ) => void;\n\nexport function startIO( self : IONode, promise : IOPromise, options : IOOptions, thenDo : ( json : any ) => any ) : IOPromise {\n // Stop pending I/O first...\n abortIO( self );\n\n self._ioPromise = promise\n .then( resp => {\n self._ioPromise = null;\n \n const result = thenDo ? thenDo( resp ) : resp;\n \n triggerAndBubble( self, 'sync', self, resp, options );\n \n return result;\n } ) \n .catch( err => {\n self._ioPromise = null;\n \n // Overlaps with a new `error` event.\n triggerAndBubble( self, 'error', self, err, options );\n \n throw err;\n } ) as IOPromise;\n\n self._ioPromise.abort = promise.abort;\n\n return self._ioPromise;\n}\n\nexport function abortIO( self : IONode ){\n if( self._ioPromise && self._ioPromise.abort ){\n self._ioPromise.abort();\n self._ioPromise = null;\n }\n}\n\nexport function triggerAndBubble( eventSource, ...args ){\n eventSource.trigger.apply( eventSource, args );\n const { collection } = eventSource;\n collection && collection.trigger.apply( collection, args ); \n}","/**\n * Traversable objects and symbolic references\n */\nexport interface Traversable {\n getStore() : Traversable\n getOwner() : Traversable\n get( key : string ) : any \n}\n\nconst referenceMask = /\\^|(store\\.[^.]+)|([^.]+)/g;\n\n// Compile reference to function\nexport type ResolveReference = ( root : Traversable ) => any; \n\nexport class CompiledReference {\n resolve : ResolveReference\n tail : string\n local : boolean\n\n constructor( reference : string, splitTail : boolean = false ){\n const path = reference\n .match( referenceMask )\n .map( key => {\n if( key === '^' || key === 'owner' ) return 'getOwner()';\n\n if( key[ 0 ] === '~' ) return `getStore().get(\"${ key.substr( 1 ) }\")`;\n\n if( key.indexOf( 'store.' ) === 0 ) return `getStore().get(\"${ key.substr( 6 ) }\")`;\n \n return key;\n } );\n \n this.tail = splitTail && path.pop();\n this.local = !path.length;\n \n this.resolve = new Function( 'self', `\n var v = self.${ path.shift() };\n \n ${ path.map( x => `\n v = v && v.${ x };\n `).join('')}\n\n return v;\n ` );\n }\n}\n\nexport function resolveReference( root : Traversable, reference : string, action : ( object, key : string ) => any ) : any {\n const path = reference.match( referenceMask ),\n skip = path.length - 1;\n \n let self = root;\n\n for( var i = 0; i < skip; i++ ){\n const key = path[ i ];\n switch( key ){\n case '~' : self = self.getStore(); break;\n case '^' : self = self.getOwner(); break;\n default : self = self.get( key );\n }\n\n // Do nothing if object on the path doesn't exist.\n if( !self ) return;\n }\n\n return action( self, path[ skip ] );\n}","export interface ChildrenErrors {\n [ key : string ] : ValidationError | any\n} \n\nexport interface Validatable {\n /** @internal */\n _validateNested( errors : ChildrenErrors ) : number;\n \n validate( self : any ) : any\n get( key : string ) : any\n}\n\n// Validation error object.\nexport class ValidationError {\n // Invalid nested object keys \n nested : ChildrenErrors \n length : number\n\n // Local error\n error : any\n\n constructor( obj : Validatable ){\n this.length = obj._validateNested( this.nested = {} );\n\n if( this.error = obj.validate( obj ) ){\n this.length++;\n }\n }\n\n each( iteratee : ( value : any, key : string ) => void ) : void {\n const { error, nested } = this;\n\n if( error ) iteratee( error, null );\n\n for( const key in nested ){\n iteratee( nested[ key ], key );\n }\n }\n\n eachError( iteratee : ( error : any, key : string, object : Validatable ) => void, object : Validatable ) : void {\n this.each( ( value : any, key : string ) => {\n if( value instanceof ValidationError ){\n (value).eachError( iteratee, object.get( key ) );\n }\n else{\n iteratee( value, key, object );\n }\n });\n }\n}","import { abortIO, IOEndpoint, IONode, IOPromise } from './io-tools';\nimport { EventCallbacks, define, definitions, eventsApi, Logger, LogLevel, Messenger, MessengerDefinition, MessengersByCid, mixinRules, mixins, MixinsState, throwingLogger } from './object-plus';\nimport { resolveReference, Traversable } from './traversable';\nimport { ChildrenErrors, Validatable, ValidationError } from './validation';\n\nconst { trigger3, on, off } = eventsApi;\n/***\n * Abstract class implementing ownership tree, tho-phase transactions, and validation. \n * 1. createTransaction() - apply changes to an object tree, and if there are some events to send, transaction object is created.\n * 2. transaction.commit() - send and process all change events, and close transaction.\n */\n\n/** @private */\nexport interface TransactionalDefinition extends MessengerDefinition {\n endpoint? : IOEndpoint\n}\n\nexport enum ItemsBehavior {\n share = 0b0001,\n listen = 0b0010,\n persistent = 0b0100\n}\n\n// Transactional object interface\n\nexport interface Transactional extends Messenger {}\n\n@define\n@definitions({\n endpoint : mixinRules.value\n})\n@mixins( Messenger )\nexport abstract class Transactional implements Messenger, IONode, Validatable, Traversable {\n // Mixins are hard in TypeScript. We need to copy type signatures over...\n // Here goes 'Mixable' mixin.\n static endpoint : IOEndpoint;\n \n /** @internal */\n static __super__ : object;\n \n static mixins : MixinsState;\n static define : ( definition? : TransactionalDefinition, statics? : object ) => typeof Transactional;\n static extend : ( definition? : T, statics? : object ) => any;\n\n static onDefine( definitions : TransactionalDefinition, BaseClass : typeof Transactional ){\n if( definitions.endpoint ) this.prototype._endpoint = definitions.endpoint;\n Messenger.onDefine.call( this, definitions, BaseClass );\n };\n\n static onExtend( BaseClass : typeof Transactional ) : void {\n // Make sure we don't inherit class factories.\n if( BaseClass.create === this.create ) {\n this.create = Transactional.create;\n }\n }\n\n // Define extendable mixin static properties.\n static create any>( this : M, a? : any, b? : any ) : InstanceType {\n return new (this as any)( a, b );\n }\n\n // State accessor.\n /** @internal */\n readonly __inner_state__ : any;\n\n // Shared modifier (used by collections of shared models)\n /** @internal */\n _shared? : number; \n \n dispose() : void {\n if( this._disposed ) return;\n \n abortIO( this );\n this._owner = void 0;\n this._ownerKey = void 0;\n this.off();\n this.stopListening();\n this._disposed = true;\n }\n \n cidPrefix : string\n\n // Unique version token replaced on change\n /** @internal */\n _changeToken : {} = {}\n\n // true while inside of the transaction\n /** @internal */\n _transaction : boolean = false;\n\n // Holds current transaction's options, when in the middle of transaction and there're changes but is an unsent change event\n /** @internal */\n _isDirty : TransactionOptions = null;\n\n // Backreference set by owner (Record, Collection, or other object)\n /** @internal */\n _owner : Owner = void 0;\n\n // Key supplied by owner. Used by record to identify attribute key.\n // Only collections doesn't set the key, which is used to distinguish collections.\n /** @internal */ \n _ownerKey : string = void 0;\n\n // Name of the change event\n /** @internal */\n _changeEventName : string\n\n /**\n * Subsribe for the changes.\n */\n onChanges( handler : Function, target? : Messenger ){\n on( this, this._changeEventName, handler, target );\n }\n\n /**\n * Unsubscribe from changes.\n */\n offChanges( handler? : Function, target? : Messenger ){\n off( this, this._changeEventName, handler, target );\n }\n\n /**\n * Listen to changes event. \n */\n listenToChanges( target : Transactional, handler ){\n this.listenTo( target, target._changeEventName, handler );\n }\n\n constructor( cid : string | number ){\n this.cid = this.cidPrefix + cid;\n }\n\n // Deeply clone ownership subtree\n abstract clone( options? : CloneOptions ) : this\n \n // Execute given function in the scope of ad-hoc transaction.\n transaction( fun : ( self : this ) => void, options : TransactionOptions = {} ) : void{\n const isRoot = transactionApi.begin( this );\n const update = fun.call( this, this );\n update && this.set( update );\n isRoot && transactionApi.commit( this );\n }\n\n // Assign transactional object \"by value\", copying aggregated items.\n assignFrom( source : Transactional | Object ) : this {\n // Need to delay change events until change token willl by synced.\n this.transaction( () =>{\n this.set( ( source ).__inner_state__ || source, { merge : true } );\n\n // Synchronize change tokens\n const { _changeToken } = source as any;\n \n if( _changeToken ){\n this._changeToken = _changeToken;\n } \n });\n\n return this;\n }\n\n // Create object from JSON. Throw if validation fail.\n static from Transactional >( this : T, json : any, { strict, ...options } : { strict? : boolean } & TransactionOptions = {} ) : InstanceType{\n const obj : Transactional = ( this as any ).create( json, { ...options, logger : strict ? throwingLogger : void 0 } );\n\n if( strict && obj.validationError ){\n obj.eachValidationError( ( error, key, obj ) => {\n throw new Error( `${ obj.getClassName() }.${ key }: ${ error }` );\n });\n }\n\n return obj as any;\n }\n\n // Apply bulk object update without any notifications, and return open transaction.\n // Used internally to implement two-phase commit.\n // Returns null if there are no any changes.\n /** @internal */\n abstract _createTransaction( values : any, options? : TransactionOptions ) : Transaction | void\n\n // Apply bulk in-place object update in scope of ad-hoc transaction \n abstract set( values : any, options? : TransactionOptions ) : this;\n\n \n // Parse function applied when 'parse' option is set for transaction.\n parse( data : any, options? : TransactionOptions ) : any { return data }\n\n // Convert object to the serializable JSON structure\n abstract toJSON( options? : object ) : {}\n\n /*******************\n * Traversals and member access\n */\n \n // Get object member by its key.\n abstract get( key : string ) : any\n\n // Get object member by symbolic reference.\n deepGet( reference : string ) : any {\n return resolveReference( this, reference, ( object, key ) => object.get ? object.get( key ) : object[ key ] );\n }\n\n //_isCollection : boolean\n\n // Return owner skipping collections.\n getOwner() : Owner {\n return this._owner;\n }\n\n // Store used when owner chain store lookup failed. Static value in the prototype. \n /** @internal */\n _defaultStore : Transactional\n\n // Locate the closest store. Store object stops traversal by overriding this method. \n getStore() : Transactional {\n const { _owner } = this;\n return _owner ? _owner.getStore() : this._defaultStore;\n }\n\n\n /***************************************************\n * Iteration API\n */\n\n // Loop through the members. Must be efficiently implemented in container class.\n\n /** @internal */\n _endpoint : IOEndpoint\n \n /** @internal */\n _ioPromise : IOPromise\n\n hasPendingIO() : IOPromise { return this._ioPromise; }\n\n //fetch( options? : object ) : IOPromise { throw new Error( \"Not implemented\" ); }\n\n getEndpoint() : IOEndpoint {\n return getOwnerEndpoint( this ) || this._endpoint;\n }\n \n /*********************************\n * Validation API\n */\n\n // Lazily evaluated validation error\n /** @internal */\n _validationError : ValidationError = void 0\n\n // Validate ownership tree and return valudation error \n get validationError() : ValidationError {\n const error = this._validationError || ( this._validationError = new ValidationError( this ) );\n return error.length ? error : null; \n }\n\n // Validate nested members. Returns errors count.\n /** @internal */\n abstract _validateNested( errors : ChildrenErrors ) : number\n\n // Object-level validator. Returns validation error.\n validate( obj? : Transactional ) : any {}\n\n // Return validation error (or undefined) for nested object with the given key. \n getValidationError( key? : string ) : any {\n var error = this.validationError;\n return ( key ? error && error.nested[ key ] : error ) || null;\n }\n\n // Get validation error for the given symbolic reference.\n deepValidationError( reference : string ) : any {\n return resolveReference( this, reference, ( object, key ) => object.getValidationError( key ) );\n }\n\n // Iterate through all validation errors across the ownership tree.\n eachValidationError( iteratee : ( error : any, key : string, object : Transactional ) => void ) : void {\n const { validationError } = this;\n validationError && validationError.eachError( iteratee, this );\n }\n\n // Check whenever member with a given key is valid. \n isValid( key? : string ) : boolean {\n return !this.getValidationError( key );\n }\n\n valueOf() : Object { return this.cid; }\n toString(){ return this.cid; }\n\n // Get class name for an object instance. Works fine with ES6 classes definitions (not in IE).\n getClassName() : string {\n const { name } = this.constructor;\n if( name !== 'Subclass' ) return name;\n }\n\n // Logging interface for run time errors and warnings.\n /** @internal */\n abstract _log( level : LogLevel, topic : string, text : string, value : any, logger? : Logger ) : void\n}\n\nexport interface CloneOptions {\n // 'Pin store' shall assign this._defaultStore = this.getStore();\n pinStore? : boolean\n}\n\n// Owner must accept children update events. It's an only way children communicates with an owner.\n/** @private */\nexport interface Owner extends Traversable, Messenger {\n /** @internal */\n _onChildrenChange( child : Transactional, options : TransactionOptions ) : void;\n \n getOwner() : Owner\n getStore() : Transactional\n}\n\n// Transaction object used for two-phase commit protocol.\n// Must be implemented by subclasses.\n// Transaction must be created if there are actual changes and when markIsDirty returns true.\n/** @private */ \nexport interface Transaction {\n // Object transaction is being made on.\n object : Transactional\n\n // Send out change events, process update triggers, and close transaction.\n // Nested transactions must be marked with isNested flag (it suppress owner notification).\n commit( initiator? : Transactional )\n}\n\n// Options for distributed transaction \nexport interface TransactionOptions {\n // Invoke parsing \n parse? : boolean\n\n // Optional logger\n logger? : Logger\n\n // Suppress change notifications and update triggers\n silent? : boolean\n\n // Update existing transactional members in place, or skip the update (ignored by models)\n merge? : boolean // =true\n\n // Should collections remove elements in set (ignored by models) \n remove? : boolean // =true\n\n // Always replace enclosed objects with new instances\n reset? : boolean // = false\n\n // Do not dispose aggregated members\n unset? : boolean\n\n validate? : boolean\n\n // IO method name if the transaction is initiated as a result of IO operation\n ioMethod? : 'save' | 'fetch'\n\n // The hint for IOEndpoint\n // If `true`, `record.save()` will behave as \"upsert\" operation for the records having id.\n upsert? : boolean\n}\n\n/**\n * Low-level transactions API. Must be used like this:\n * const isRoot = begin( record );\n * ...\n * isRoot && commit( record, options );\n * \n * When committing nested transaction, the flag must be set to true. \n * commit( object, options, isNested ) \n */\n\nexport const transactionApi = {\n // Start transaction. Return true if it's the root one.\n /** @private */\n begin( object : Transactional ) : boolean {\n return object._transaction ? false : ( object._transaction = true ); \n },\n\n // Mark object having changes inside of the current transaction.\n // Returns true whenever there notifications are required.\n /** @private */\n markAsDirty( object : Transactional, options : TransactionOptions ) : boolean {\n // If silent option is in effect, don't set isDirty flag.\n const dirty = !options.silent;\n if( dirty ) object._isDirty = options;\n \n // Reset version token.\n object._changeToken = {};\n\n // Object is changed, so validation must happen again. Clear the cache.\n object._validationError = void 0;\n\n return dirty;\n },\n\n // Commit transaction. Send out change event and notify owner. Returns true if there were changes.\n // Must be executed for the root transaction only.\n /** @private */\n commit( object : Transactional, initiator? : Transactional ){\n let originalOptions = object._isDirty;\n\n if( originalOptions ){\n // Send the sequence of change events, handling chained handlers.\n while( object._isDirty ){\n const options = object._isDirty;\n object._isDirty = null; \n trigger3( object, object._changeEventName, object, options, initiator );\n }\n \n // Mark transaction as closed.\n object._transaction = false;\n\n // Notify owner on changes out of transaction scope. \n const { _owner } = object; \n if( _owner && _owner !== initiator ){ // If it's the nested transaction, owner is already aware there are some changes.\n _owner._onChildrenChange( object, originalOptions );\n }\n }\n else{\n // No changes. Silently close transaction.\n object._isDirty = null;\n object._transaction = false;\n }\n },\n\n /************************************\n * Ownership management\n */\n\n // Add reference to the record.\n /** @private */\n aquire( owner : Owner, child : Transactional, key? : string ) : void {\n if( child._owner ) throw new ReferenceError( 'Trying to aquire ownership for an object already having an owner' );\n\n child._owner = owner;\n child._ownerKey = key;\n },\n\n // Remove reference to the record.\n /** @private */\n free( owner : Owner, child : Transactional ) : void {\n if( owner === child._owner ){\n child._owner = void 0;\n child._ownerKey = void 0;\n }\n }\n}\n\nfunction getOwnerEndpoint( self : Transactional ) : IOEndpoint {\n // Check if we are the member of the collection...\n const { collection } = self as any;\n if( collection ){\n return getOwnerEndpoint( collection );\n }\n\n // Now, if we're the member of the model...\n if( self._owner ){\n const { _endpoints } = self._owner as any;\n return _endpoints && _endpoints[ self._ownerKey ];\n }\n}\n","import { eventsApi } from '../object-plus';\nimport { Owner, Transaction, Transactional, transactionApi, TransactionOptions } from \"../transactions\";\nconst { begin : _begin, markAsDirty : _markAsDirty, commit } = transactionApi;\n\nconst { trigger3 } = eventsApi;\n\nexport interface ConstructorsMixin {\n Attributes : AttributesConstructor\n AttributesCopy : AttributesCopyConstructor\n}\n\nexport interface ConstructorOptions extends TransactionOptions{\n clone? : boolean\n}\n\nexport type AttributesConstructor = new ( record : AttributesContainer, values : object, options : TransactionOptions ) => AttributesValues;\nexport type AttributesCopyConstructor = new ( values : object ) => AttributesValues;\n\nexport interface AttributesContainer extends Transactional, Owner, ConstructorsMixin {\n // Attribute descriptors.\n /** @internal */\n _attributes : AttributesDescriptors\n\n // Attribute values.\n attributes : AttributesValues\n\n // Previous attribute values.\n /** @internal */\n _previousAttributes : AttributesValues\n\n // Changed attributes cache. \n /** @internal */\n _changedAttributes : AttributesValues\n}\n\nexport interface AttributesValues {\n [ name : string ] : any\n}\n\nexport interface AttributesDescriptors {\n [ name : string ] : AttributeUpdatePipeline\n}\n\nexport interface AttributeUpdatePipeline{\n doUpdate( value, record : AttributesContainer, options : TransactionOptions, nested? : Transaction[] ) : boolean\n}\n\n // Optimized single attribute transactional update. To be called from attributes setters\n // options.silent === false, parse === false. \nexport function setAttribute( record : AttributesContainer, name : string, value : any ) : void {\n // Open the transaction.\n const isRoot = begin( record ),\n options = {};\n\n // Update attribute. \n if( record._attributes[ name ].doUpdate( value, record, options ) ){\n // Notify listeners on changes.\n markAsDirty( record, options );\n trigger3( record, 'change:' + name, record, record.attributes[ name ], options );\n }\n\n // Close the transaction.\n isRoot && commit( record );\n}\n\nfunction begin( record : AttributesContainer ){\n if( _begin( record ) ){\n record._previousAttributes = new record.AttributesCopy( record.attributes );\n record._changedAttributes = null;\n return true;\n }\n \n return false;\n}\n\nfunction markAsDirty( record : AttributesContainer, options : TransactionOptions ){\n // Need to recalculate changed attributes, when we have nested set in change:attr handler\n if( record._changedAttributes ){\n record._changedAttributes = null;\n }\n\n return _markAsDirty( record, options );\n}\n\n/**\n * TODO: There's an opportunity to create an optimized pipeline for primitive types and Date, which makes the majority\n * of attributes. It might create the major speedup.\n * \n * Create the dedicated pipeline for owned and shared attributes as well.\n * \n * Three elements of the pipeline:\n * - from constructor\n * - from assignment\n * - from `set`\n */\n\nexport const UpdateRecordMixin = {\n// Need to override it here, since begin/end transaction brackets are overriden. \n transaction( this : AttributesContainer, fun : ( self : AttributesContainer ) => void, options : TransactionOptions = {} ) : void{\n const isRoot = begin( this );\n fun.call( this, this );\n isRoot && commit( this );\n },\n \n // Handle nested changes. TODO: propagateChanges == false, same in transaction.\n _onChildrenChange( child : Transactional, options : TransactionOptions ) : void {\n const { _ownerKey } = child,\n attribute = this._attributes[ _ownerKey ];\n\n if( !attribute /* TODO: Must be an opposite, likely the bug */ || attribute.propagateChanges ) this.forceAttributeChange( _ownerKey, options );\n },\n\n // Simulate attribute change \n forceAttributeChange( key : string, options : TransactionOptions = {} ){\n // Touch an attribute in bounds of transaction\n const isRoot = begin( this );\n\n if( markAsDirty( this, options ) ){\n trigger3( this, 'change:' + key, this, this.attributes[ key ], options );\n }\n \n isRoot && commit( this );\n },\n\n _createTransaction( this : AttributesContainer, a_values : {}, options : TransactionOptions = {} ) : Transaction {\n const isRoot = begin( this ),\n changes : string[] = [],\n nested : RecordTransaction[]= [],\n { _attributes } = this,\n values = options.parse ? this.parse( a_values, options ) : a_values;\n\n let unknown;\n\n if( shouldBeAnObject( this, values, options ) ){\n for( let name in values ){\n const spec = _attributes[ name ];\n\n if( spec ){\n if( spec.doUpdate( values[ name ], this, options, nested ) ){\n changes.push( name );\n }\n }\n else{\n unknown || ( unknown = [] );\n unknown.push( `'${ name }'` );\n }\n }\n\n if( unknown ){\n unknownAttrsWarning( this, unknown, { values }, options );\n }\n }\n \n if( changes.length && markAsDirty( this, options ) ){\n return new RecordTransaction( this, isRoot, nested, changes );\n }\n \n // No changes, but there might be silent attributes with open transactions.\n for( let pendingTransaction of nested ){\n pendingTransaction.commit( this );\n }\n\n isRoot && commit( this );\n }\n};\n\nexport function unknownAttrsWarning( record : AttributesContainer, unknown : string[], props, options ){\n record._log( 'warn', 'Type-R:UnknownAttrs', `undefined attributes ${ unknown.join(', ')} are ignored.`, props, options.logger );\n}\n\n// One of the main performance tricks of Type-R.\n// Create loop unrolled constructors for internal attribute hash,\n// so the hidden class JIT optimization will be engaged and they will become static structs.\n// It dramatically improves record performance.\nexport function constructorsMixin( attrDefs : AttributesDescriptors ) : ConstructorsMixin {\n const attrs = Object.keys( attrDefs );\n\n const AttributesCopy : AttributesCopyConstructor = new Function( 'values', `\n ${ attrs.map( attr =>`\n this.${ attr } = values.${ attr };\n `).join( '' ) }\n `) as any;\n\n AttributesCopy.prototype = Object.prototype;\n\n const Attributes : AttributesConstructor = new Function( 'record', 'values', 'options', `\n var _attrs = record._attributes;\n\n ${ attrs.map( attr =>`\n this.${ attr } = _attrs.${ attr }.doInit( values.${ attr }, record, options );\n `).join( '' ) }\n `) as any;\n\n Attributes.prototype = Object.prototype;\n\n return { Attributes, AttributesCopy };\n}\n\nexport function shouldBeAnObject( record : AttributesContainer, values : object, options ){\n if( values && values.constructor === Object ) return true;\n\n record._log( 'error', 'Type-R:InvalidObject', 'update with non-object is ignored!', { values }, options.logger );\n return false;\n}\n\n// Transaction class. Implements two-phase transactions on object's tree. \n// Transaction must be created if there are actual changes and when markIsDirty returns true. \nexport class RecordTransaction implements Transaction {\n // open transaction\n constructor( public object : AttributesContainer,\n public isRoot : boolean,\n public nested : Transaction[],\n public changes : string[] ){}\n\n // commit transaction\n commit( initiator? : AttributesContainer ) : void {\n const { nested, object, changes } = this;\n\n // Commit all pending nested transactions...\n for( let transaction of nested ){ \n transaction.commit( object );\n }\n\n // Notify listeners on attribute changes...\n // Transaction is never created when silent option is set, so just send events out.\n const { attributes, _isDirty } = object;\n for( let key of changes ){\n trigger3( object, 'change:' + key, object, attributes[ key ], _isDirty );\n }\n\n this.isRoot && commit( object, initiator );\n }\n}","import { IOEndpoint } from '../../io-tools';\nimport { LogLevel, tools, Logger } from '../../object-plus';\nimport { TransactionOptions } from '../../transactions';\nimport { AttributesContainer, AttributeUpdatePipeline, RecordTransaction, setAttribute } from '../updates';\n\nconst { notEqual, assign} = tools;\n\nexport type Transform = ( this : AnyType, next : any, prev : any, record : AttributesContainer, options : TransactionOptions ) => any;\nexport type ChangeHandler = ( this : AnyType, next : any, prev : any, record : AttributesContainer, options : TransactionOptions ) => void;\n\nexport interface AttributeOptions {\n _metatype? : typeof AnyType\n validate? : ( record : AttributesContainer, value : any, key : string ) => any\n isRequired? : boolean\n changeEvents? : boolean\n\n endpoint? : IOEndpoint\n\n type? : Function\n value? : any\n hasCustomDefault? : boolean\n\n parse? : Parse\n toJSON? : AttributeToJSON\n \n getHooks? : GetHook[]\n transforms? : Transform[]\n changeHandlers? : ChangeHandler[]\n\n _onChange? : ChangeAttrHandler\n}\n\nexport type Parse = ( value : any, key? : string ) => any;\nexport type GetHook = ( value : any, key? : string ) => any;\nexport type AttributeToJSON = ( value : any, key? : string ) => any\nexport type AttributeParse = ( value : any, key? : string ) => any\nexport type ChangeAttrHandler = ( ( value : any, attr? : string ) => void ) | string;\n\n// TODO: interface differs from options, do something obout it\nconst emptyOptions : TransactionOptions = {};\n\n/**\n * Typeless attribute. Is the base class for all other attributes.\n */\nexport class AnyType implements AttributeUpdatePipeline {\n // Factory method to create attribute from options \n static create : ( options : AttributeOptions, name : string ) => AnyType;\n \n /**\n * Update pipeline functions\n * =========================\n *\n * Stage 0. canBeUpdated( value )\n * - presence of this function implies attribute's ability to update in place.\n */\n canBeUpdated( prev, next, options : TransactionOptions ) : any {}\n\n /**\n * Stage 1. Transform stage\n */\n transform( next : any, prev : any, model : AttributesContainer, options : TransactionOptions ) : any { return next; }\n\n // convert attribute type to `this.type`.\n convert( next : any, prev : any, model : AttributesContainer, options : TransactionOptions ) : any { return next; }\n\n /**\n * Stage 2. Check if attr value is changed\n */\n isChanged( a : any, b : any ) : boolean {\n return notEqual( a, b );\n }\n\n /**\n * Stage 3. Handle attribute change\n */\n handleChange( next : any, prev : any, model : AttributesContainer, options : TransactionOptions ) {}\n\n /**\n * End update pipeline definitions.\n */\n\n // create empty object passing backbone options to constructor...\n create() { return void 0; }\n\n // generic clone function for typeless attributes\n // Must be overriden in sublass\n clone( value : any, record : AttributesContainer ) {\n return value;\n }\n\n dispose( record : AttributesContainer, value : any ) : void {\n this.handleChange( void 0, value, record, emptyOptions );\n }\n\n validate( record : AttributesContainer, value : any, key : string ) : any {}\n\n toJSON( value, key, options? : object ) {\n return value && value.toJSON ? value.toJSON( options ) : value;\n }\n\n createPropertyDescriptor() : PropertyDescriptor | void {\n const { name, getHook } = this;\n\n if( name !== 'id' ){\n return {\n // call to optimized set function for single argument.\n set( value ){\n setAttribute( this, name, value );\n },\n\n // attach get hook to the getter function, if it present\n get : (\n getHook ?\n function() {\n return getHook.call( this, this.attributes[ name ], name );\n } :\n function() { return this.attributes[ name ]; }\n ),\n\n configurable : true\n }\n }\n }\n\n value : any\n\n // Used as global default value for the given metatype\n static defaultValue : any;\n\n type : Function\n\n initialize( name : string, options : TransactionOptions ){}\n\n options : AttributeOptions\n\n doInit( value, record : AttributesContainer, options : TransactionOptions ){\n const v = value === void 0 ? this.defaultValue() : value,\n x = this.transform( v, void 0, record, options );\n \n this.handleChange( x, void 0, record, options );\n return x;\n }\n\n doUpdate( value, record : AttributesContainer, options : TransactionOptions, nested? : RecordTransaction[] ){\n const { name } = this,\n { attributes } = record,\n prev = attributes[ name ];\n\n const next = this.transform( value, prev, record, options );\n attributes[ name ] = next;\n\n if( this.isChanged( next, prev ) ) {\n // Do the rest of the job after assignment\n this.handleChange( next, prev, record, options );\n return true;\n }\n\n return false;\n }\n\n propagateChanges : boolean\n\n protected _log( level : LogLevel, code : string, text : string, value, record : AttributesContainer, logger : Logger ){\n record._log( level, code, `${record.getClassName()}.${ this.name } ${ text }`, {\n 'New value' : value,\n 'Prev. value' : record.attributes[ this.name ]\n }, logger );\n }\n\n defaultValue(){\n return this.value;\n }\n\n constructor( public name : string, a_options : AttributeOptions ) { \n // Save original options...\n this.options = a_options;\n\n // Clone options.\n const options : AttributeOptions = { getHooks : [], transforms : [], changeHandlers : [], ...a_options };\n options.getHooks = options.getHooks.slice();\n options.transforms = options.transforms.slice();\n options.changeHandlers = options.changeHandlers.slice();\n\n const {\n value, type, parse, toJSON, changeEvents,\n validate, getHooks, transforms, changeHandlers\n } = options;\n\n // Initialize default value...\n this.value = value;\n this.type = type;\n\n // TODO: An opportunity to optimize for attribute subtype.\n if( !options.hasCustomDefault && type ){\n this.defaultValue = this.create;\n }\n else if( tools.isValidJSON( value ) ){ \n // JSON literals must be deep copied.\n this.defaultValue = new Function( `return ${ JSON.stringify( value ) };` ) as any;\n }\n else{\n this.defaultValue = this.defaultValue;\n }\n\n // Changes must be bubbled when they are not disabled for an attribute and transactional object.\n this.propagateChanges = changeEvents !== false;\n\n this.toJSON = toJSON === void 0 ? this.toJSON : toJSON;\n\n this.validate = validate || this.validate;\n \n if( options.isRequired ){\n this.validate = wrapIsRequired( this.validate );\n }\n\n /**\n * Assemble pipelines...\n */\n\n // `convert` is default transform, which is always present...\n transforms.unshift( this.convert );\n\n // Get hook from the attribute will be used first...\n if( this.get ) getHooks.unshift( this.get );\n\n // let subclasses configure the pipeline...\n this.initialize.call( this, options );\n\n // let attribute spec configure the pipeline...\n if( getHooks.length ){\n const getHook = this.getHook = getHooks.reduce( chainGetHooks );\n\n const { validate } = this;\n this.validate = function( record : AttributesContainer, value : any, key : string ){\n return validate.call( this, record, getHook.call( record, value, key ), key );\n }\n }\n \n this.transform = transforms.length ? transforms.reduce( chainTransforms ) : this.transform;\n \n this.handleChange = changeHandlers.length ? changeHandlers.reduce( chainChangeHandlers ) : this.handleChange;\n\n // Attribute-level parse transform are attached as update hooks modifiers...\n const { doInit, doUpdate } = this;\n this.doInit = parse ? function( value, record : AttributesContainer, options : TransactionOptions ){\n return doInit.call( this, options.parse && value !== void 0 ? parse.call( record, value, this.name ) : value, record, options );\n } : doInit;\n\n this.doUpdate = parse ? function( value, record : AttributesContainer, options : TransactionOptions, nested? : RecordTransaction[] ){\n return doUpdate.call( this, options.parse && value !== void 0 ? parse.call( record, value, this.name ) : value, record, options, nested );\n } : doUpdate;\n }\n\n getHook : ( value, key : string ) => any = null\n get : ( value, key : string ) => any\n}\n\n\nfunction chainGetHooks( prevHook : GetHook, nextHook : GetHook ) : GetHook {\n return function( value, name ) {\n return nextHook.call( this, prevHook.call( this, value, name ), name );\n }\n}\n\nfunction chainTransforms( prevTransform : Transform, nextTransform : Transform ) : Transform {\n return function( next, prev, record, options ) {\n return nextTransform.call( this, prevTransform.call( this, next, prev, record, options ), prev, record, options );\n }\n}\n\nfunction chainChangeHandlers( prevHandler : ChangeHandler, nextHandler : ChangeHandler ) : ChangeHandler {\n return function( next, prev, record, options ) {\n prevHandler.call( this, next, prev, record, options );\n nextHandler.call( this, next, prev, record, options );\n }\n}\n\nfunction wrapIsRequired( validate ){\n return function( record : AttributesContainer, value : any, key : string ){\n return value ? validate.call( this, record, value, key ) : 'Required';\n }\n}","/**\n * Built-in JSON types attributes: Object, Array, Number, String, Boolean, and immutable class.\n * \n * Adds type assertions, default validation, and optimized update pipeline.\n */\n\nimport { TransactionOptions } from '../../transactions';\nimport { AnyType } from './any';\nimport { AttributesContainer } from '../updates';\n\n/**\n * Custom class must be immutable class which implements toJSON() method\n * with a constructor taking json.\n */\nexport class ImmutableClassType extends AnyType {\n type : new ( value? : any ) => {}\n\n create(){\n return new this.type();\n }\n\n convert( next : any ) : any {\n return next == null || next instanceof this.type ? next : new this.type( next );\n }\n\n toJSON( value, key? : string, options? : object ){\n return value && value.toJSON ? value.toJSON( options ) : value;\n }\n\n clone( value ) {\n return new this.type( this.toJSON( value ) );\n }\n\n isChanged( a, b ){\n return a !== b;\n }\n}\n\n/**\n * Optimized attribute of primitive type.\n * \n * Primitives has specialized simplified pipeline.\n */\nexport class PrimitiveType extends AnyType {\n type : NumberConstructor | StringConstructor | BooleanConstructor\n\n dispose(){}\n create() { return this.type(); }\n\n toJSON( value ) { return value; }\n\n convert( next ) { return next == null ? next : this.type( next ); }\n\n isChanged( a, b ) { return a !== b; }\n\n clone( value ) { return value; }\n\n doInit( value, record : AttributesContainer, options : TransactionOptions ){\n return this.transform( value === void 0 ? this.value : value, void 0, record, options );\n }\n\n doUpdate( value, record, options, nested ){\n const { name } = this,\n { attributes } = record,\n prev = attributes[ name ];\n \n return prev !== ( attributes[ name ] = this.transform( value, prev, record, options ) );\n }\n\n initialize(){\n if( !this.options.hasCustomDefault ){\n this.value = this.type();\n }\n }\n}\n\n// Number type with special validation algothim.\n/** @private */ \nexport class NumericType extends PrimitiveType {\n type : NumberConstructor\n\n create(){\n return 0;\n }\n\n convert( next, prev?, record?, options? ) {\n const num = next == null ? next : this.type( next );\n\n if( num !== num ){\n this._log( 'error', 'Type-R:InvalidNumber', 'Number attribute is assigned with an invalid number', next, record, options.logger );\n }\n \n return num;\n }\n\n validate( model, value, name ) {\n // Whatever is not symmetrically serializable to JSON, is not valid by default.\n if( value != null && !isFinite( value ) ) {\n return name + ' is not valid number';\n }\n }\n}\n\n/**\n * Compatibility wrapper for Array type.\n * @private\n */ \nexport class ArrayType extends AnyType {\n toJSON( value ) { return value; }\n dispose(){}\n create(){ return []; }\n\n convert( next, prev, record, options ) {\n // Fix incompatible constructor behaviour of Array...\n if( next == null || Array.isArray( next ) ) return next;\n\n this._log( 'error', 'Type-R:InvalidArray', 'Array attribute assigned with non-array value', next, record, options.logger );\n\n return [];\n }\n\n clone( value ){\n return value && value.slice();\n }\n}\n\nexport class ObjectType extends AnyType {\n create(){ return {}; }\n\n convert( next, prev, record, options ) {\n if( next == null || typeof next === 'object' ) return next;\n \n this._log( 'error', 'Type-R:InvalidObject', 'Object attribute is assigned with non-object value', next, record, options.logger );\n return {};\n }\n}\n\nexport function doNothing(){}\n\nexport class FunctionType extends AnyType {\n // Functions are not serialized.\n toJSON( value ) { return void 0; }\n create(){ return doNothing; }\n dispose(){}\n\n convert( next, prev, record, options ) {\n // Fix incompatible constructor behaviour of Function...\n if( next == null || typeof next === 'function' ) return next;\n\n this._log( 'error', 'Type-R:InvalidFunction', 'Function attribute assigned with non-function value', next, record, options.logger );\n\n return doNothing;\n }\n\n // Functions are not cloned.\n clone( value ){ return value; }\n}\n","/**\n * Date attribute type.\n * \n * Implements validation, cross-browser compatibility fixes, variety of Date serialization formats,\n * and optimized update pipeline.\n */\nimport { TransactionOptions } from '../../transactions';\nimport { AnyType } from './any';\nimport { AttributesContainer } from '../updates';\n\n// Date Attribute\n/** @private */\nexport class DateType extends AnyType {\n create(){\n return new Date();\n }\n \n convert( next : any, a, record, options ){\n if( next == null || next instanceof Date ) return next;\n\n const date = new Date( next ),\n timestamp = date.getTime();\n\n if( timestamp !== timestamp ){\n this._log( 'error', 'Type-R:InvalidDate', 'Date attribute assigned with invalid date', next, record, options.logger );\n }\n\n return date;\n }\n\n validate( model, value, name ) {\n if( value != null ){\n const timestamp = value.getTime(); \n if( timestamp !== timestamp ) return name + ' is Invalid Date';\n }\n }\n\n toJSON( value ) { return value && value.toISOString(); }\n\n isChanged( a, b ) { return ( a && a.getTime() ) !== ( b && b.getTime() ); }\n\n doInit( value, record : AttributesContainer, options : TransactionOptions ){\n // Date don't have handleChanges step.\n return this.transform( value === void 0 ? this.defaultValue() : value, void 0, record, options );\n }\n\n doUpdate( value, record, options, nested ){\n const { name } = this,\n { attributes } = record,\n prev = attributes[ name ];\n \n // Date don't have handleChanges step.\n return this.isChanged( prev , attributes[ name ] = this.transform( value, prev, record, options ) );\n }\n\n clone( value ) { return value && new Date( value.getTime() ); }\n dispose(){}\n}\n\n// If ISO date is not supported by date constructor (such as in Safari), polyfill it.\nfunction supportsDate( date ){\n return !isNaN( ( new Date( date ) ).getTime() );\n}\n\nif( !supportsDate('2011-11-29T15:52:30.5') ||\n !supportsDate('2011-11-29T15:52:30.52') ||\n !supportsDate('2011-11-29T15:52:18.867') ||\n !supportsDate('2011-11-29T15:52:18.867Z') ||\n !supportsDate('2011-11-29T15:52:18.867-03:30') ){\n\n DateType.prototype.convert = function( value ){\n return value == null || value instanceof Date ? value : new Date( safeParseDate( value ) );\n }\n}\n\nconst numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ],\n isoDatePattern = /^(\\d{4}|[+\\-]\\d{6})(?:-(\\d{2})(?:-(\\d{2}))?)?(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:(Z)|([+\\-])(\\d{2})(?::(\\d{2}))?)?)?$/;\n\nfunction safeParseDate( date : string ) : number {\n var timestamp, struct : any[], minutesOffset = 0;\n\n if( ( struct = isoDatePattern.exec( date )) ) {\n // avoid NaN timestamps caused by undefined values being passed to Date.UTC\n for( var i = 0, k; ( k = numericKeys[ i ] ); ++i ) {\n struct[ k ] = +struct[ k ] || 0;\n }\n\n // allow undefined days and months\n struct[ 2 ] = (+struct[ 2 ] || 1) - 1;\n struct[ 3 ] = +struct[ 3 ] || 1;\n\n if( struct[ 8 ] !== 'Z' && struct[ 9 ] !== undefined ) {\n minutesOffset = struct[ 10 ] * 60 + struct[ 11 ];\n\n if( struct[ 9 ] === '+' ) {\n minutesOffset = 0 - minutesOffset;\n }\n }\n\n timestamp =\n Date.UTC( struct[ 1 ], struct[ 2 ], struct[ 3 ], struct[ 4 ], struct[ 5 ] + minutesOffset, struct[ 6 ],\n struct[ 7 ] );\n }\n else {\n timestamp = Date.parse( date );\n }\n\n return timestamp;\n}","import { ItemsBehavior, Transactional, transactionApi, TransactionOptions } from '../../transactions';\nimport { ValidationError } from '../../validation';\nimport { AnyType } from './any';\nimport { AttributesContainer, ConstructorOptions } from '../updates';\n\nconst { free, aquire } = transactionApi;\n\nexport class AggregatedType extends AnyType {\n type : typeof Transactional\n\n clone( value : Transactional ) : Transactional {\n return value ? value.clone() : value;\n }\n\n toJSON( x, key : string, options : object ){ return x && x.toJSON( options ); }\n\n doInit( value, record : AttributesContainer, options : ConstructorOptions ){\n const v = options.clone ? this.clone( value ) : (\n value === void 0 ? this.defaultValue() : value\n );\n\n const x = this.transform( v, void 0, record, options );\n this.handleChange( x, void 0, record, options );\n return x;\n }\n\n doUpdate( value, record, options, nested : any[] ){ // Last to things can be wrapped to an object, either transaction or ad-hoc\n const key = this.name, { attributes } = record; \n const prev = attributes[ key ];\n let update;\n\n // This can be moved to transactional attribute. And chained with the rest.\n if( update = this.canBeUpdated( prev, value, options ) ) { // todo - skip empty updates.\n const nestedTransaction = prev._createTransaction( update, options );\n if( nestedTransaction ){\n if( nested ){\n nested.push( nestedTransaction );\n }\n else{\n nestedTransaction.commit( record );\n }\n\n if( this.propagateChanges ) return true;\n }\n\n return false;\n }\n\n const next = this.transform( value, prev, record, options );\n attributes[ key ] = next;\n\n if( this.isChanged( next, prev ) ) { // Primitives and nested comparison can be inlined.\n // Do the rest of the job after assignment\n this.handleChange( next, prev, record, options );\n\n return true;\n }\n\n return false;\n }\n\n canBeUpdated( prev : Transactional, next : any, options : TransactionOptions ) : any {\n // If an object already exists, and new value is of incompatible type, let object handle the update.\n if( prev && next != null ){\n if( next instanceof this.type ){\n // In case if merge option explicitly specified, force merge.\n if( options.merge ) return next.__inner_state__;\n }\n else{\n return next;\n }\n }\n }\n\n convert( next : any, prev : any, record : AttributesContainer, options : TransactionOptions ) : Transactional {\n // Invoke class factory to handle abstract classes\n if( next == null ) return next;\n \n if( next instanceof this.type ){\n if( next._shared && !( next._shared & ItemsBehavior.persistent ) ) { // TODO: think more about shared types assignment compatibility. \n this._log( 'error', 'Type-R:InvalidCollection', 'aggregated collection attribute is assigned with shared collection type', next, record, options.logger );\n }\n\n // With explicit 'merge' option we need to clone an object if its previous value was 'null'.\n // This is an only case we could be here when merge === true.\n if( options.merge ) return next.clone();\n\n if( next._owner ){\n this._log( 'warn', 'Type-R:InvalidOwner', 'object alreay has an owner and was cloned. Use explicit object.clone() to dismiss this warning.', next, record, options.logger );\n return next.clone();\n }\n\n return next;\n }\n\n return ( this.type as any).create( next, options );\n }\n\n dispose ( record : AttributesContainer, value : Transactional ){\n if( value ){\n this.handleChange( void 0, value, record, {} );\n }\n }\n\n validate( record : AttributesContainer, value : Transactional ) : ValidationError {\n var error = value && value.validationError;\n if( error ) return error;\n }\n\n create() : Transactional {\n return (this.type).create(); // this the subclass of Transactional here.\n }\n\n initialize( options ){\n options.changeHandlers.unshift( this._handleChange );\n }\n\n _handleChange( next : Transactional, prev : Transactional, record : AttributesContainer, options : TransactionOptions ){\n if( prev ){\n free( record, prev );\n options.unset || prev.dispose();\n } \n \n if( next ) aquire( record, next, this.name );\n }\n}","import { eventsApi } from '../../object-plus';\nimport { ItemsBehavior, Transactional, transactionApi, TransactionOptions } from '../../transactions';\nimport { AnyType } from './any';\nimport { AttributesContainer, ConstructorOptions } from '../updates';\nimport { ChainableAttributeSpec } from '../attrDef';\n\nconst { on, off } = eventsApi,\n { free, aquire } = transactionApi;\n\n/************************\n * Shared attribute definition.\n * - Not serialized.\n * - Listening to the changes.\n * - Doesn't take ownership when assigned with object of proper type.\n * - Takes ownership on objects which are converted.\n */\n\nconst shareAndListen = ItemsBehavior.listen | ItemsBehavior.share;\n\n/** @private */\nexport class SharedType extends AnyType {\n type : typeof Transactional\n\n doInit( value, record : AttributesContainer, options : ConstructorOptions ){\n const v = options.clone ? this.clone( value, record ) : (\n value === void 0 ? this.defaultValue() : value\n );\n\n const x = this.transform( v, void 0, record, options );\n this.handleChange( x, void 0, record, options );\n return x;\n }\n\n doUpdate( value, record, options, nested : any[] ){ // Last to things can be wrapped to an object, either transaction or ad-hoc\n const key = this.name, { attributes } = record; \n const prev = attributes[ key ];\n let update;\n\n // This can be moved to transactional attribute. And chained with the rest.\n if( update = this.canBeUpdated( prev, value, options ) ) { // todo - skip empty updates.\n const nestedTransaction = prev._createTransaction( update, options );\n if( nestedTransaction ){\n if( nested ){\n nested.push( nestedTransaction );\n }\n else{\n nestedTransaction.commit( record );\n }\n\n if( this.propagateChanges ) return true;\n }\n\n return false;\n }\n\n const next = this.transform( value, prev, record, options );\n attributes[ key ] = next;\n\n if( this.isChanged( next, prev ) ) { // Primitives and nested comparison can be inlined.\n // Do the rest of the job after assignment\n this.handleChange( next, prev, record, options );\n\n return true;\n }\n\n return false;\n }\n\n clone( value : Transactional, record : AttributesContainer ) : Transactional {\n // References are not cloned.\n if( !value || value._owner !== record ) return value;\n\n // Implicitly created objects are cloned.\n const clone = value.clone();\n aquire( record, clone, this.name );\n return clone;\n }\n\n // Do not serialize by default.\n toJSON(){}\n\n canBeUpdated( prev : Transactional, next : any, options : TransactionOptions ) : any {\n // If an object already exists, and new value is of incompatible type, let object handle the update.\n if( prev && next != null && !( next instanceof this.type ) ){\n return next;\n }\n }\n\n convert( next : any, prev : any, record : AttributesContainer, options : TransactionOptions ) : Transactional {\n if( next == null || next instanceof this.type ) return next;\n\n // Convert type using implicitly created transactional object.\n const implicitObject = new ( this.type as any )( next, options, shareAndListen );\n\n // To prevent a leak, we need to take an ownership on it.\n aquire( record, implicitObject, this.name );\n\n return implicitObject;\n }\n\n // Refs are always valid.\n validate( model, value, name ){}\n\n // They are always created as null.\n create() : Transactional {\n return null;\n }\n\n // Listening to the change events\n _handleChange( next : Transactional, prev : Transactional, record : AttributesContainer, options ){\n if( prev ){\n // If there was an implicitly created object, remove an ownership.\n if( prev._owner === record ){\n free( record, prev );\n options.unset || prev.dispose();\n }\n else{\n off( prev, prev._changeEventName, this._onChange, record );\n }\n } \n \n if( next ){\n // No need to take an ownership for an implicit object - already done in convert or clone.\n if( next._owner !== record ){\n on( next, next._changeEventName, this._onChange, record );\n }\n } \n }\n\n dispose( record : AttributesContainer, value : Transactional ){\n if( value ){\n this.handleChange( void 0, value, record, {} );\n }\n }\n\n _onChange : ( child : Transactional, options : TransactionOptions, initiator : Transactional ) => void \n\n initialize( options ){\n // Create change event handler which knows current attribute name. \n const attribute = this;\n this._onChange = this.propagateChanges ? function( child, options, initiator ){\n this === initiator || this.forceAttributeChange( attribute.name, options );\n } : ignore;\n\n options.changeHandlers.unshift( this._handleChange );\n }\n}\n\nfunction ignore(){}","import { PrimitiveType, NumericType, ObjectType, ImmutableClassType, FunctionType, ArrayType } from './basic';\nimport { DateType } from './date';\nimport { AnyType, AttributeOptions } from './any';\n\nexport * from './any';\nexport * from './basic';\nexport * from './date';\nexport * from './owned';\nexport * from './shared';\n\n/**\n * Every record attribute type has the corresponding metatype controlling its behavior.\n * For built-in types, Type-R uses the predefined list to resolve metatype in order to avoid global objects modifications.\n * For user-defined types, static `_metatype` constructor member is used.\n */\n\nconst builtins : Function[] = [ String, Number, Boolean, Date, Object, Array, Function ],\n metatypes = [ PrimitiveType, NumericType, PrimitiveType, DateType, ObjectType, ArrayType, FunctionType ];\n\nexport function getMetatype( Ctor : Function ){\n return ( Ctor as any )._metatype || resolveBuiltins( Ctor );\n}\n\nAnyType.create = ( options : AttributeOptions, name : string ) => {\n const type = options.type,\n AttributeCtor = options._metatype || ( type ? getMetatype( type ): AnyType );\n\n return new AttributeCtor( name, options );\n}\n\nfunction resolveBuiltins( Ctor : Function ){\n const idx = builtins.indexOf( Ctor );\n return idx < 0 ? ImmutableClassType : metatypes[ idx ];\n}","/**\n * Type spec engine. Declare attributes using chainable syntax,\n * and returns object with spec.\n */\nimport { IOEndpoint } from '../io-tools';\nimport { definitionDecorator, EventMap, EventsDefinition, tools } from '../object-plus';\nimport { Transactional } from '../transactions';\nimport { AttributeOptions, AttributeToJSON, getMetatype, Parse, SharedType } from './metatypes';\nimport { AttributesContainer } from './updates';\n\nconst { assign } = tools;\n\nexport interface AttributeCheck {\n ( value : any, key : string ) : boolean\n error? : any\n}\n\n// Infer the proper TS type from a Type-R attribute spec.\nexport type Infer =\n A extends ChainableAttributeSpec ? TrueReturnType :\n A extends Function ? TrueReturnType :\n A;\n \n// Extract the proper TS return type for a function or constructor.\ntype TrueReturnType =\n F extends DateConstructor ? Date :\n F extends ( ...args : any[] ) => infer R ? R :\n F extends new ( ...args : any[] ) => infer R ? R :\n void;\n\nexport class ChainableAttributeSpec{\n options : AttributeOptions & { type? : F };\n\n constructor( options : AttributeOptions ) {\n // Shallow copy options, fill it with defaults.\n this.options = { getHooks : [], transforms : [], changeHandlers : []};\n if( options ) assign( this.options, options );\n }\n\n check( check : AttributeCheck, error? : any ) : this {\n function validate( model, value, name ){\n if( !check.call( model, value, name ) ){\n const msg = error || check.error || name + ' is not valid';\n return typeof msg === 'function' ? msg.call( model, name ) : msg;\n }\n }\n\n const prev = this.options.validate;\n\n return this.metadata({\n validate : prev ? (\n function( model, value, name ){\n return prev( model, value, name ) || validate( model, value, name );\n }\n ) : validate\n });\n }\n\n get as() : PropertyDecorator {\n return definitionDecorator( 'attributes', this );\n }\n\n get isRequired() : this {\n return this.required;\n }\n\n get required() : this {\n return this.metadata({ isRequired : true }); \n }\n\n endpoint( endpoint : IOEndpoint ) : this {\n return this.metadata({ endpoint });\n }\n\n watcher( ref : string | ( ( value : any, key : string ) => void ) ) : this {\n return this.metadata({ _onChange : ref });\n }\n\n // Attribute-specific parse transform\n parse( fun : Parse ) : this {\n return this.metadata({ parse : fun });\n }\n\n toJSON( fun : AttributeToJSON) : this {\n return this.metadata({\n toJSON : typeof fun === 'function' ? fun : ( fun ? ( x, k, o ) => x && x.toJSON( o ) : emptyFunction ) \n });\n }\n\n // Attribute get hook.\n get( fun ) : this {\n return this.metadata({\n getHooks : this.options.getHooks.concat( fun )\n });\n }\n\n // Attribute set hook.\n set( fun ) : this {\n function handleSetHook( next, prev, record : AttributesContainer, options ) {\n if( this.isChanged( next, prev ) ) {\n const changed = fun.call( record, next, this.name );\n return changed === void 0 ? prev : this.convert( changed, prev, record, options );\n }\n\n return prev;\n }\n\n return this.metadata({\n transforms : this.options.transforms.concat( handleSetHook )\n });\n }\n\n changeEvents( events : boolean ) : this {\n return this.metadata({ changeEvents : events });\n }\n\n // Subsribe to events from an attribute.\n events( map : EventsDefinition ) : this {\n const eventMap = new EventMap( map );\n\n function handleEventsSubscribtion( next, prev, record : AttributesContainer ){\n prev && prev.trigger && eventMap.unsubscribe( record, prev );\n\n next && next.trigger && eventMap.subscribe( record, next );\n }\n\n return this.metadata({\n changeHandlers : this.options.changeHandlers.concat( handleEventsSubscribtion )\n });\n }\n\n // Creates a copy of the spec.\n get has() : this {\n return this;\n }\n\n metadata( options : object ) : this {\n const cloned = new ChainableAttributeSpec( this.options );\n assign( cloned.options, options );\n return cloned as any;\n }\n\n value( x ) : this {\n return this.metadata({ value : x, hasCustomDefault : true });\n }\n\n static from( spec : any ) : ChainableAttributeSpec {\n // Pass metatype through untouched...\n if( spec && spec instanceof ChainableAttributeSpec ) {\n return spec;\n }\n\n return typeof spec === 'function' ? type( spec ) : value( spec );\n }\n}\n\nfunction emptyFunction(){}\n\nexport function type( this : void, Type : ChainableAttributeSpec | F, value? : any ) : ChainableAttributeSpec {\n if( Type instanceof ChainableAttributeSpec ) return Type;\n\n const attrDef = new ChainableAttributeSpec({ type : Type }),\n defaultValue = Type && value === void 0 ? getMetatype( Type ).defaultValue : value;\n\n return defaultValue === void 0 ? attrDef : attrDef.value( defaultValue );\n}\n\nexport function shared( this : void, Constructor : C ) : ChainableAttributeSpec {\n return new ChainableAttributeSpec({\n value : null,\n type : Constructor,\n _metatype : SharedType\n });\n}\n\n// Create attribute metatype inferring the type from the value.\nexport function value( this : void, x : any ) : ChainableAttributeSpec {\n const Type = inferType( x ),\n // Transactional types inferred from values must have shared type. \n AttrDef = Type && Type.prototype instanceof Transactional ? shared( Type ) :\n type( Type );\n\n return AttrDef.value( x );\n}\n\nfunction inferType( value : any ) : Function {\n switch( typeof value ) {\n case 'number' :\n return Number;\n case 'string' :\n return String;\n case 'boolean' :\n return Boolean;\n case 'function' :\n return Function;\n case 'undefined' :\n return void 0;\n case 'object' :\n return value ? value.constructor : void 0;\n }\n}","import { IOEndpoint } from '../io-tools';\nimport { eventsApi, tools as _ } from '../object-plus';\nimport { CompiledReference } from '../traversable';\nimport { ChainableAttributeSpec } from './attrDef';\nimport { AnyType } from './metatypes';\nimport { ConstructorsMixin, constructorsMixin } from './updates';\n\nexport interface RecordAttributesMixin extends ConstructorsMixin {\n // Attributes descriptors\n _attributes : AttributeDescriptors\n _attributesArray : AnyType[]\n \n // Attribute's property descriptors\n properties : PropertyDescriptorMap\n\n // Event map for record's local events.\n _localEvents? : eventsApi.EventMap,\n\n _endpoints : { [ name : string ] : IOEndpoint }\n}\n\nexport interface AttributeDescriptors {\n [ name : string ] : AnyType\n}\n\n// Create attribute from the type spec.\nexport function createAttribute( spec : any, name : string ) : AnyType {\n return AnyType.create( ChainableAttributeSpec.from( spec ).options, name );\n}\n\n// Create record mixin from the given record's attributes definition\nexport function createAttributesMixin( attributesDefinition : object, baseClassAttributes : AttributeDescriptors ) : RecordAttributesMixin {\n const myAttributes = _.transform( {} as AttributeDescriptors, attributesDefinition, createAttribute ),\n allAttributes = _.defaults( {} as AttributeDescriptors, myAttributes, baseClassAttributes );\n\n const ConstructorsMixin = constructorsMixin( allAttributes );\n\n return {\n ...ConstructorsMixin,\n _attributes : new ConstructorsMixin.AttributesCopy( allAttributes ),\n _attributesArray : Object.keys( allAttributes ).map( key => allAttributes[ key ] ),\n properties : _.transform( {}, myAttributes, x => x.createPropertyDescriptor() ),\n ...localEventsMixin( myAttributes ),\n _endpoints : _.transform( {}, allAttributes, attrDef => attrDef.options.endpoint )\n } \n}\n\ninterface LocalEventsMixin {\n _localEvents? : eventsApi.EventMap\n}\n\nfunction localEventsMixin( attrSpecs : AttributeDescriptors ) : LocalEventsMixin {\n let _localEvents : eventsApi.EventMap;\n\n for( var key in attrSpecs ){\n const attribute = attrSpecs[ key ],\n { _onChange } = attribute.options; \n\n if( _onChange ){\n _localEvents || ( _localEvents = new eventsApi.EventMap() );\n\n _localEvents.addEvent( 'change:' + key,\n typeof _onChange === 'string' ?\n createWatcherFromRef( _onChange, key ) : \n wrapWatcher( _onChange, key ) );\n }\n }\n\n return _localEvents ? { _localEvents } : {};\n}\n\nfunction wrapWatcher( watcher, key ){\n return function( record, value ){\n watcher.call( record, value, key );\n } \n}\n\nfunction createWatcherFromRef( ref : string, key : string ){\n const { local, resolve, tail } = new CompiledReference( ref, true );\n return local ?\n function( record, value ){\n record[ tail ]( value, key );\n } :\n function( record, value ){\n resolve( record )[ tail ]( value, key );\n }\n}","import { IOEndpoint, IONode, IOOptions, IOPromise, startIO } from '../io-tools';\nimport { TransactionOptions } from '../transactions';\n\nexport interface IORecord extends IONode {\n getEndpoint() : IOEndpoint\n save( options? : object ) : IOPromise\n fetch( options? : object ) : IOPromise\n destroy( options? : object ) : IOPromise\n toJSON( options? : object ) : any\n parse( data : any, options? : object ) : any\n isNew() : boolean\n id : string | number\n set( json : object, options : TransactionOptions ) : this\n}\n\nexport const IORecordMixin = {\n save( this : IORecord, options : IOOptions = {} ){\n const endpoint = this.getEndpoint(),\n json = this.toJSON({ ioMethod : 'save', ...options });\n\n return startIO(\n this,\n this.isNew() ?\n endpoint.create( json, options, this ) :\n endpoint.update( this.id, json, options, this ),\n options,\n\n update => {\n this.set( update, {\n parse : true,\n ioMethod : 'save',\n ...options\n } );\n }\n );\n },\n\n fetch( options : IOOptions = {} ){\n return startIO(\n this,\n this.getEndpoint().read( this.id, options, this ),\n options,\n\n json => this.set( json, { parse : true, ioMethod : 'fetch', ...options } )\n );\n },\n\n destroy( options : IOOptions = {} ){ \n return startIO(\n this,\n this.getEndpoint().destroy( this.id, options, this ),\n options,\n\n () => {\n const { collection } = this;\n if( collection ){\n collection.remove( this, options );\n }\n else{\n this.dispose();\n }\n\n return this;\n }\n )\n }\n}","/**\n * Record core implementing transactional updates.\n * The root of all definitions. \n */\n\nimport { CollectionConstructor } from '../collection';\nimport { IOEndpoint } from '../io-tools';\nimport { define, definitions, isProduction, Logger, logger, LogLevel, mixinRules, TheType, tools } from '../object-plus';\nimport { CloneOptions, Owner, Transaction, Transactional, TransactionalDefinition, TransactionOptions } from '../transactions';\nimport { ChildrenErrors } from '../validation';\nimport { Infer, type } from './attrDef';\nimport { IORecord, IORecordMixin } from './io-mixin';\nimport { AggregatedType, AnyType } from './metatypes';\nimport { AttributesConstructor, AttributesContainer, AttributesCopyConstructor, AttributesValues, setAttribute, shouldBeAnObject, unknownAttrsWarning, UpdateRecordMixin } from './updates';\n\n\nconst { assign, isEmpty } = tools;\n\n/*******************************************************\n * Record core implementation\n */\n\nexport interface ConstructorOptions extends TransactionOptions{\n clone? : boolean\n}\n\n// Client unique id counter\nlet _cidCounter : number = 0;\n\n/***************************************************************\n * Record Definition as accepted by Record.define( definition )\n */\nexport interface RecordDefinition extends TransactionalDefinition {\n idAttribute? : string\n attributes? : AttributesValues\n collection? : object\n Collection? : typeof Transactional\n}\n\nexport interface RecordConstructor extends TheType {\n new ( attrs? : Partial, options? : object ) : Record & A\n prototype : Record\n Collection : CollectionConstructor\n}\n\nexport type InferAttrs = {\n [K in keyof A]: Infer\n};\n\nexport type AttributesMixin = InferAttrs\n\n@define({\n // Default client id prefix \n cidPrefix : 'm',\n\n // Name of the change event\n _changeEventName : 'change',\n\n // Default id attribute name\n idAttribute : 'id'\n})\n@definitions({\n defaults : mixinRules.merge,\n attributes : mixinRules.merge,\n collection : mixinRules.merge,\n Collection : mixinRules.value,\n idAttribute : mixinRules.protoValue\n})\nexport class Record extends Transactional implements IORecord, AttributesContainer, Iterable {\n /** @internal */\n static _metatype = AggregatedType;\n\n // Hack\n static onDefine( definition, BaseClass ){}\n\n static Collection : CollectionConstructor;\n static DefaultCollection : CollectionConstructor;\n \n // Attribute type for the record id.\n static id = type( String ).value( null );\n \n // Lazy object reference, serializable as id.\n static get ref(){\n return type( this )\n .toJSON( x => x ? x.id : null )\n .parse( x => {\n return { [ this.prototype.idAttribute ] : x };\n });\n }\n\n static extendAttrs( this : T, attrs : A ) : RecordConstructor & InferAttrs> {\n return this.defaults( attrs ) as any;\n }\n\n static defaults( attrs : AttributesValues ) : typeof Record {\n return this.extend({ attributes : attrs }) as any;\n }\n \n static attributes : AttributesValues\n\n /********************\n * IO Methods\n */\n /** @internal */\n _endpoints : { [ name : string ] : IOEndpoint }\n\n /***********************************\n * Core Members\n */\n previousAttributes(){ return new this.AttributesCopy( this._previousAttributes ); } \n\n // Polymorphic accessor for aggregated attribute's canBeUpdated().\n /** @internal */\n get __inner_state__(){ return this.attributes; }\n\n get changed(){\n let changed = this._changedAttributes;\n\n if( !changed ){\n const prev = this._previousAttributes;\n changed = {};\n\n const { attributes } = this;\n\n for( let attr of this._attributesArray ){\n const key = attr.name,\n value = attributes[ key ];\n\n if( attr.isChanged( value, prev[ key ] ) ){\n changed[ key ] = value;\n }\n }\n\n this._changedAttributes = changed;\n }\n\n return changed; \n }\n\n changedAttributes( diff? : {} ) : boolean | {} {\n if( !diff ) return this.hasChanged() ? { ...this.changed } : false;\n\n var val, changed : {} | boolean = false,\n old = this._transaction ? this._previousAttributes : this.attributes,\n attrSpecs = this._attributes;\n\n for( var attr in diff ){\n if( !attrSpecs[ attr ].isChanged( old[ attr ], ( val = diff[ attr ] ) ) ) continue;\n (changed || (changed = {}))[ attr ] = val;\n }\n\n return changed; \n }\n\n hasChanged( key? : string ) : boolean {\n const { _previousAttributes } = this;\n if( !_previousAttributes ) return false;\n\n return key ?\n this._attributes[ key ].isChanged( this.attributes[ key ], _previousAttributes[ key ] ) :\n !isEmpty( this.changed );\n }\n\n previous( key : string ) : any {\n if( key ){\n const { _previousAttributes } = this;\n if( _previousAttributes ) return _previousAttributes[ key ];\n }\n \n return null;\n }\n\n isNew() : boolean {\n return this.id == null;\n }\n\n has( key : string ) : boolean {\n return this[ key ] != void 0;\n }\n\n // Return attribute value, setting an attribute to undefined.\n // TODO: If attribute was aggregated, don't dispose it.\n unset( key : string, options? ) : any {\n const value = this[ key ];\n this.set({ [ key ] : void 0 }, { unset : true, ...options });\n return value;\n }\n\n // Undocumented. Move to NestedTypes?\n clear( options? ) : this {\n const nullify = options && options.nullify;\n\n this.transaction( () =>{\n this.forEach( ( value, key ) => this[ key ] = nullify ? null : void 0 );\n }, options );\n\n return this;\n }\n\n // Returns Record owner skipping collections. TODO: Move out\n getOwner() : Owner {\n const owner : any = this._owner;\n\n // If there are no key, owner must be transactional object, and it's the collection.\n // We don't expect that collection can be the member of collection, so we're skipping just one level up. An optimization.\n return this._ownerKey ? owner : owner && owner._owner;\n }\n\n /***********************************\n * Identity managements\n */\n\n // Id attribute name ('id' by default)\n idAttribute : string;\n\n // Fixed 'id' property pointing to id attribute\n get id() : string { return this.attributes[ this.idAttribute ]; }\n set id( x : string ){ setAttribute( this, this.idAttribute, x ); }\n\n /***********************************\n * Dynamically compiled stuff\n */\n\n // Attributes specifications\n /** @internal */\n _attributes : { [ key : string ] : AnyType }\n\n /** @internal */\n _attributesArray : AnyType[]\n\n // Attributes object copy constructor\n Attributes : AttributesConstructor\n AttributesCopy : AttributesCopyConstructor\n\n // Create record default values, optionally augmenting given values.\n defaults( values = {} ){\n const defaults = {},\n { _attributesArray } = this;\n\n for( let attr of _attributesArray ){\n const key = attr.name,\n value = values[ key ];\n\n defaults[ key ] = value === void 0 ? attr.defaultValue() : value;\n }\n\n return defaults;\n }\n\n /***************************************************\n * Record construction\n */\n // Create record, optionally setting an owner\n constructor( a_values? : any, a_options? : ConstructorOptions ){\n super( _cidCounter++ );\n this.attributes = {};\n \n const options = a_options || {},\n values = ( options.parse ? this.parse( a_values, options ) : a_values ) || {};\n\n isProduction || typeCheck( this, values, options );\n\n this._previousAttributes = this.attributes = new this.Attributes( this, values, options );\n\n this.initialize( a_values, a_options );\n\n if( this._localEvents ) this._localEvents.subscribe( this, this );\n }\n\n // Initialization callback, to be overriden by the subclasses \n initialize( values? : Partial, options? ){}\n\n // Deeply clone record, optionally setting new owner.\n clone( options : CloneOptions = {} ) : this {\n const copy : this = new (this.constructor)( this.attributes, { clone : true } );\n \n if( options.pinStore ) copy._defaultStore = this.getStore();\n\n return copy;\n }\n\n /** @internal */\n _validateNested( errors : ChildrenErrors ) : number {\n var length = 0;\n\n const { attributes } = this;\n\n for( let attribute of this._attributesArray ){\n const { name } = attribute,\n error = attribute.validate( this, attributes[ name ], name );\n\n if( error ){\n errors[ name ] = error;\n length++;\n }\n }\n\n return length;\n }\n\n // Get attribute by key\n get( key : string ) : any {\n return this[ key ];\n }\n\n // Apply bulk in-place object update in scope of ad-hoc transaction \n set( values : any, options? : TransactionOptions ) : this {\n if( values ){ \n const transaction = this._createTransaction( values, options );\n transaction && transaction.commit();\n }\n\n return this;\n }\n\n /**\n * Serialization control\n */\n\n // Default record-level serializer, to be overriden by subclasses \n toJSON( options? : TransactionOptions ) : any {\n const json = {},\n { attributes } = this;\n\n for( let attribute of this._attributesArray ){\n const { name } = attribute,\n value = attributes[ name ];\n\n if( value !== void 0 ){\n // ...serialize it according to its spec.\n const asJson = attribute.toJSON.call( this, value, name, options );\n\n // ...skipping undefined values. Such an attributes are excluded.\n if( asJson !== void 0 ) json[ name ] = asJson; \n }\n }\n\n return json;\n }\n \n // Default record-level parser, to be overriden by the subclasses.\n parse( data, options? : TransactionOptions ){\n return data;\n }\n\n /**\n * Transactional control\n */\n deepSet( name : string, value : any, options? : any ){\n // Operation might involve series of nested object updates, thus it's wrapped in transaction.\n this.transaction( () => {\n const path = name.split( '.' ),\n l = path.length - 1,\n attr = path[ l ];\n\n let model = this;\n\n // Locate the model, traversing the path.\n for( let i = 0; i < l; i++ ){\n const key = path[ i ];\n\n // There might be collections in path, so use `get`.\n let next = model.get ? model.get( key ) : model[ key ];\n\n // Create models, if they are not exist.\n if( !next ){\n const attrSpecs = model._attributes;\n if( attrSpecs ){\n // If current object is model, create default attribute\n var newModel = attrSpecs[ key ].create();\n\n // If created object is model, nullify attributes when requested\n if( options && options.nullify && newModel._attributes ){\n newModel.clear( options );\n }\n\n model[ key ] = next = newModel;\n }\n // Silently fail in other case.\n else return;\n }\n \n model = next;\n }\n\n // Set model attribute.\n if( model.set ){\n model.set({ [ attr ] : value }, options );\n }\n else{\n model[ attr ] = value;\n }\n });\n\n return this;\n }\n \n // Returns owner without the key (usually it's collection)\n get collection() : any {\n return this._ownerKey ? null : this._owner;\n }\n\n // Dispose object and all childrens\n dispose(){\n if( this._disposed ) return;\n\n const { attributes } = this;\n\n for( let attr of this._attributesArray ){\n attr.dispose( this, attributes[ attr.name ] );\n }\n \n super.dispose();\n }\n\n /** @internal */\n _log( level : LogLevel, topic: string, text : string, props : object, a_logger? : Logger ) : void {\n ( a_logger || logger ).trigger( level, topic, this.getClassName() + ' ' + text, {\n ...props,\n 'Record' : this,\n 'Attributes definition' : this._attributes\n });\n }\n\n getClassName() : string {\n return super.getClassName() || 'Record';\n }\n\n /** @internal */\n _createTransaction( values : object, options : TransactionOptions ) : Transaction { return void 0; }\n // Simulate attribute change \n forceAttributeChange : ( key : string, options : TransactionOptions ) => void\n\n /** @internal */\n _onChildrenChange : ( child : Transactional, options : TransactionOptions ) => void\n\n\n /**\n * Map methods\n */\n\n forEach( iteratee : ( value? : any, key? : string ) => void, context? : any ){\n const fun = context !== void 0 ? ( v, k ) => iteratee.call( context, v, k ) : iteratee,\n { attributes } = this;\n\n for( const key in this.attributes ){\n const value = attributes[ key ];\n if( value !== void 0 ) fun( value, key );\n }\n }\n\n mapObject( a_fun : ( value, key ) => any, context? : any ) : object {\n const fun = context === void 0 ? a_fun : a_fun.bind( context );\n return tools.transform( {}, this.attributes, fun );\n }\n\n [ Symbol.iterator ](){\n return new RecordEntriesIterator( this );\n }\n\n entries(){\n return new RecordEntriesIterator( this );\n }\n\n // Get array of attribute keys (Record) or record ids (Collection) \n keys() : string[] {\n const keys : string[] = [];\n\n this.forEach( ( value, key ) => keys.push( key ) );\n\n return keys;\n }\n};\n\nexport interface Record extends IORecord {}\nexport interface Record extends AttributesContainer {}\n\n\nassign( Record.prototype, UpdateRecordMixin, IORecordMixin );\n\n/***********************************************\n * Helper functions\n */\n\nclass BaseRecordAttributes {\n id : string\n\n constructor( record : Record, x : AttributesValues, options : TransactionOptions ) {\n this.id = x.id;\n }\n}\n\nRecord.prototype.Attributes = BaseRecordAttributes;\n\nclass BaseRecordAttributesCopy {\n id : string\n\n constructor( x : AttributesValues ) {\n this.id = x.id;\n }\n}\n\nRecord.prototype.AttributesCopy = BaseRecordAttributesCopy;\n\nconst IdAttribute = AnyType.create({ value : void 0 }, 'id' );\nRecord.prototype._attributes = { id : IdAttribute };\nRecord.prototype._attributesArray = [ IdAttribute ];\n\nfunction typeCheck( record : Record, values : object, options ){\n if( shouldBeAnObject( record, values, options ) ){\n const { _attributes } = record;\n let unknown : string[];\n\n for( let name in values ){\n if( !_attributes[ name ] ){\n unknown || ( unknown = [] );\n unknown.push( `'${ name }'` );\n }\n }\n\n if( unknown ){\n unknownAttrsWarning( record, unknown, { values }, options );\n }\n }\n}\n\nexport class RecordEntriesIterator implements Iterator<[string, any]> {\n private idx = 0;\n \n constructor( private readonly record : Record){}\n\n next() : IteratorResult<[string, any]> {\n const { record } = this,\n metatype = record._attributesArray[ this.idx++ ];\n\n return {\n done : !metatype,\n value : metatype ? [ metatype.name, record[ metatype.name ] ] : void 0\n };\n }\n}","import { define, predefine, tools } from '../object-plus';\nimport { Transactional } from '../transactions';\nimport { type } from './attrDef';\nimport { createAttributesMixin } from './mixin';\nimport { InferAttrs, Record, RecordConstructor, RecordDefinition } from './record';\n\nexport * from './attrDef';\nexport * from './metatypes';\nexport { AttributesMixin, InferAttrs, RecordConstructor } from './record';\nexport { Record };\n\nconst { assign, defaults } = tools;\n\nexport function attributes( attrDefs : D ) : RecordConstructor> {\n @define class DefaultRecord extends Record {\n static attributes = attrDefs;\n }\n\n return DefaultRecord as any;\n}\n\nRecord.onExtend = function( this : typeof Record, BaseClass : typeof Record ){\n Transactional.onExtend.call( this, BaseClass );\n\n // Create the default collection\n const Class = this;\n\n @predefine class DefaultCollection extends BaseClass.Collection {\n static model = Class;\n }\n\n this.DefaultCollection = DefaultCollection;\n\n // If there are no collection defined in statics, use the default collection.\n // It will appear in onDefine's definition, overriding all other settings.\n if( Class.Collection === BaseClass.Collection ){\n this.Collection = DefaultCollection;\n }\n}\n\nRecord.onDefine = function( definition : RecordDefinition, BaseClass : typeof Record ){\n const baseProto : Record = BaseClass.prototype;\n\n // Compile attributes spec, creating definition mixin.\n const { properties, _localEvents, ...dynamicMixin } = createAttributesMixin( this.attributes = getAttributes( definition ), baseProto._attributes );\n assign( this.prototype, dynamicMixin );\n \n definition.properties = defaults( definition.properties || {}, properties );\n definition._localEvents = _localEvents;\n \n Transactional.onDefine.call( this, definition, BaseClass );\n\n // Finalize the definition of the default collection.\n this.DefaultCollection.define( definition.collection || {} );\n\n // assign collection from the definition.\n this.Collection = definition.Collection;\n this.Collection.prototype.model = this;\n\n if( definition.endpoint ) this.Collection.prototype._endpoint = definition.endpoint; \n}\n\nfunction getAttributes({ defaults, attributes, idAttribute } : RecordDefinition ) {\n const definition = attributes || defaults || {};\n \n // If there is an undeclared idAttribute, add its definition as untyped generic attribute.\n if( idAttribute && !( idAttribute in definition ) ){\n definition[ idAttribute ] = void 0;\n }\n\n return definition;\n}\n\ndeclare var Reflect;\n\nexport function auto( value : any ) : PropertyDecorator;\nexport function auto( proto : object, attrName : string ) : void;\nexport function auto( proto, attrName? : string ) : any {\n if( typeof Reflect !== 'undefined' && Reflect.getMetadata ){\n if( attrName ){\n type( Reflect.getMetadata( \"design:type\", proto, attrName ) ).as( proto, attrName );\n }\n else{\n const value = proto;\n return ( proto : object, attrName : string ) : void => {\n type( Reflect.getMetadata( \"design:type\", proto, attrName ) ).value( value ).as( proto, attrName );\n }\n } \n }\n else{\n proto._log( 'error', 'Type-R:MissingImport', 'Add import \"reflect-metadata\"; as the first line of your app.' );\n } \n}","import { eventsApi, Logger } from '../object-plus';\nimport { Record } from '../record';\nimport { ItemsBehavior, Owner, Transaction, Transactional, transactionApi, TransactionOptions } from '../transactions';\n\n\nconst { trigger2, trigger3, on, off } = eventsApi,\n { commit } = transactionApi,\n _aquire = transactionApi.aquire, _free = transactionApi.free;\n\n/** @private */\nexport interface CollectionCore extends Transactional, Owner {\n /** @internal */\n _byId : IdIndex\n\n models : Record[]\n model : typeof Record\n idAttribute : string // TODO: Refactor inconsistent idAttribute usage\n \n /** @internal */\n _comparator : Comparator\n \n get( objOrId : string | Record | Object ) : Record \n \n /** @internal */\n _itemEvents? : eventsApi.EventMap\n /** @internal */\n _shared : number\n /** @internal */\n _aggregationError : Record[]\n /** @internal */\n _log( level : string, topic : string, text : string, value : any, logger : Logger ) : void\n}\n\n// Collection's manipulation methods elements\nexport type Elements = ( Object | Record )[];\n\nexport interface CollectionOptions extends TransactionOptions {\n sort? : boolean\n}\n\nexport type Comparator = ( a : Record, b : Record ) => number; \n\n/** @private */\nexport function dispose( collection : CollectionCore ) : Record[]{\n const { models } = collection;\n\n collection.models = [];\n collection._byId = {};\n\n freeAll( collection, models );\n return models;\n}\n\n/** @private */\nexport function convertAndAquire( collection : CollectionCore, attrs : {} | Record, options : CollectionOptions ){\n const { model } = collection;\n \n let record : Record;\n\n if( collection._shared ){\n record = attrs instanceof model ? attrs : model.create( attrs, options );\n\n if( collection._shared & ItemsBehavior.listen ){\n on( record, record._changeEventName, collection._onChildrenChange, collection );\n }\n }\n else{\n record = attrs instanceof model ? ( options.merge ? attrs.clone() : attrs ) : model.create( attrs, options );\n\n if( record._owner ){\n if( record._owner !== collection ){\n _aquire( collection, record.clone() );\n const errors = collection._aggregationError || ( collection._aggregationError = [] );\n errors.push( record );\n }\n }\n else{\n _aquire( collection, record ); \n }\n } \n\n // Subscribe for events...\n const { _itemEvents } = collection;\n _itemEvents && _itemEvents.subscribe( collection, record );\n\n return record;\n}\n\n/** @private */\nexport function free( owner : CollectionCore, child : Record, unset? : boolean ) : void {\n if( owner._shared ){\n if( owner._shared & ItemsBehavior.listen ){\n off( child, child._changeEventName, owner._onChildrenChange, owner );\n }\n }\n else{\n _free( owner, child );\n unset || child.dispose();\n }\n\n const { _itemEvents } = owner;\n _itemEvents && _itemEvents.unsubscribe( owner, child );\n}\n\n/** @private */\nexport function freeAll( collection : CollectionCore, children : Record[] ) : Record[] {\n for( let child of children ){\n free( collection, child );\n }\n\n return children;\n}\n\n/**\n * Silently sort collection, if its required. Returns true if sort happened.\n * @private\n */ \nexport function sortElements( collection : CollectionCore, options : CollectionOptions ) : boolean {\n let { _comparator } = collection;\n if( _comparator && options.sort !== false ){\n collection.models.sort( _comparator );\n return true;\n }\n\n return false;\n}\n\n/**********************************\n * Collection Index\n * @private \n */\nexport interface IdIndex {\n [ id : string ] : Record\n}\n\n/** @private Add record */ \nexport function addIndex( index : IdIndex, model : Record ) : void {\n index[ model.cid ] = model;\n var id = model.id;\n \n if( id || ( id as any ) === 0 ){\n index[ id ] = model;\n }\n}\n\n/** @private Remove record */ \nexport function removeIndex( index : IdIndex, model : Record ) : void {\n delete index[ model.cid ];\n var id = model.id;\n if( id || ( id as any ) === 0 ){\n delete index[ id ];\n }\n}\n\nexport function updateIndex( index : IdIndex, model : Record ){\n delete index[ model.previous( model.idAttribute ) ];\n\n const { id } = model;\n id == null || ( index[ id ] = model );\n}\n\n/***\n * In Collections, transactions appears only when\n * add remove or change events might be emitted.\n * reset doesn't require transaction.\n * \n * Transaction holds information regarding events, and knows how to emit them.\n * \n * Two major optimization cases.\n * 1) Population of an empty collection\n * 2) Update of the collection (no or little changes) - it's crucial to reject empty transactions.\n */\n\n\n// Transaction class. Implements two-phase transactions on object's tree.\n/** @private */ \nexport class CollectionTransaction implements Transaction {\n // open transaction\n constructor( public object : CollectionCore,\n public isRoot : boolean,\n public added : Record[],\n public removed : Record[],\n public nested : Transaction[],\n public sorted : boolean ){}\n\n // commit transaction\n commit( initiator? : Transactional ){\n const { nested, object } = this,\n { _isDirty } = object;\n\n // Commit all nested transactions...\n for( let transaction of nested ){\n transaction.commit( object );\n }\n\n if( object._aggregationError ){\n logAggregationError( object, _isDirty );\n }\n\n // Just trigger 'change' on collection, it must be already triggered for models during nested commits.\n // ??? TODO: do it in nested transactions loop? This way appears to be more correct. \n for( let transaction of nested ){\n trigger2( object, 'change', transaction.object, _isDirty );\n }\n\n // Notify listeners on attribute changes...\n const { added, removed } = this;\n\n // Trigger `add` events for both model and collection.\n for( let record of added ){\n trigger3( record, 'add', record, object, _isDirty );\n trigger3( object, 'add', record, object, _isDirty );\n }\n\n // Trigger `remove` events for both model and collection.\n for( let record of removed ){\n trigger3( record, 'remove', record, object, _isDirty );\n trigger3( object, 'remove', record, object, _isDirty );\n }\n\n if( this.sorted ){\n trigger2( object, 'sort', object, _isDirty );\n }\n\n if( added.length || removed.length ){\n trigger2( object, 'update', object, _isDirty );\n }\n\n this.isRoot && commit( object, initiator );\n }\n}\n\nexport function logAggregationError( collection : CollectionCore, options : TransactionOptions ){\n collection._log( 'warn', 'Type-R:InvalidOwner', 'added records already have an owner and were cloned. Use explicit record.clone() to dismiss this warning.', collection._aggregationError, options.logger );\n collection._aggregationError = void 0;\n}","import { Record } from '../record';\nimport { Transaction, transactionApi } from '../transactions';\nimport { addIndex, CollectionCore, CollectionOptions, CollectionTransaction, convertAndAquire, logAggregationError, sortElements, updateIndex } from './commons';\n\nconst { begin, commit, markAsDirty } = transactionApi;\n\nexport interface AddOptions extends CollectionOptions {\n at? : number \n}\n\n/** @private */\nexport function addTransaction( collection : CollectionCore, items : any[], options : AddOptions, merge? : boolean ){\n const isRoot = begin( collection ),\n nested : Transaction[]= [];\n\n var added = appendElements( collection, items, nested, options, merge );\n\n if( added.length || nested.length ){\n let needSort = sortOrMoveElements( collection, added, options );\n if( markAsDirty( collection, options ) ){\n return new CollectionTransaction( collection, isRoot, added, [], nested, needSort );\n }\n\n if( collection._aggregationError ) logAggregationError( collection, options );\n }\n\n // No changes...\n isRoot && commit( collection );\n};\n\n// Handle sort or insert at options for add operation. Reurns true if sort happened.\n/** @private */ \nfunction sortOrMoveElements( collection : CollectionCore, added : Record[], options : AddOptions ) : boolean {\n let at = options.at;\n\n // if `at` option is given, it overrides sorting option...\n if( at != null ){\n // Take an original collection's length. \n const length = collection.models.length - added.length;\n\n // Crazy Backbone rules about `at` index. I don't know what that guys smoke.\n at = Number( at );\n if( at < 0 ) at += length + 1;\n if( at < 0 ) at = 0;\n if( at > length ) at = length;\n\n // Move added elements to desired position. In place.\n moveElements( collection.models, at, added );\n return false;\n }\n\n return sortElements( collection, options );\n}\n\n/** @private */\nfunction moveElements( source : any[], at : number, added : any[] ) : void {\n for( var j = source.length - 1, i = j - added.length; i >= at; i--, j-- ){\n source[ j ] = source[ i ];\n }\n\n for( i = 0, j = at; i < added.length; i++, j++ ){\n source[ j ] = added[ i ];\n }\n}\n\n// append data to model and index\n/** @private */\nfunction appendElements( collection : CollectionCore, a_items : any[], nested : Transaction[], a_options : AddOptions, forceMerge : boolean ){\n var { _byId, models } = collection,\n merge = ( forceMerge || a_options.merge ) && !collection._shared,\n parse = a_options.parse,\n idAttribute = collection.model.prototype.idAttribute,\n prevLength = models.length;\n\n for( const item of a_items ){\n let model = item ? _byId[ item[ idAttribute ] ] || _byId[ item.cid ] : null;\n\n if( model ){\n if( merge && item !== model ){\n var attrs = item.attributes || item;\n const transaction = model._createTransaction( attrs, a_options );\n transaction && nested.push( transaction );\n\n if( model.hasChanged( idAttribute ) ){\n updateIndex( _byId, model );\n }\n }\n }\n else{\n model = convertAndAquire( collection, item, a_options );\n models.push( model );\n addIndex( _byId, model );\n }\n }\n\n return models.slice( prevLength );\n}\n","/*************\n * Remove items from collections.\n * \n * Cannot be a part of two-phase transaction on object tree.\n * Can be executed in the scope of ad-hoc transaction or from the trigger, though.\n *\n * Implemented with low-level API. \n * Most frequent operation - single element remove. Thus, it have the fast-path.\n */\n\nimport { eventsApi } from '../object-plus';\nimport { Record } from '../record';\nimport { transactionApi, TransactionOptions } from '../transactions';\nimport { CollectionCore, CollectionTransaction, free, removeIndex } from './commons';\n\nconst { trigger2, trigger3 } = eventsApi,\n { markAsDirty, begin, commit } = transactionApi;\n\n/** @private */\nexport function removeOne( collection : CollectionCore, el : Record | {} | string, options : TransactionOptions ) : Record {\n var model : Record = collection.get( el );\n\n if( model ){\n const isRoot = begin( collection ),\n models = collection.models;\n\n // Remove model form the collection. \n models.splice( models.indexOf( model ), 1 );\n removeIndex( collection._byId, model );\n \n // Mark transaction as dirty. \n const notify = markAsDirty( collection, options );\n\n // Send out events.\n if( notify ){\n trigger3( model, 'remove', model, collection, options );\n trigger3( collection, 'remove', model, collection, options );\n } \n\n free( collection, model, options.unset );\n\n notify && trigger2( collection, 'update', collection, options );\n\n // Commit transaction.\n isRoot && commit( collection );\n\n return model;\n }\n};\n\n/** Optimized for removing many elements\n * 1. Remove elements from the index, checking for duplicates\n * 2. Create new models array matching index\n * 3. Send notifications and remove references\n */\n\n/** @private */\nexport function removeMany( collection : CollectionCore, toRemove : any[], options ){\n const removed = _removeFromIndex( collection, toRemove, options.unset );\n if( removed.length ){\n const isRoot = begin( collection );\n\n _reallocate( collection, removed.length );\n\n if( markAsDirty( collection, options ) ){\n const transaction = new CollectionTransaction( collection, isRoot, [], removed, [], false );\n transaction.commit();\n }\n else{\n // Commit transaction.\n isRoot && commit( collection );\n }\n }\n\n return removed;\n};\n\n// remove models from the index...\n/** @private */\nfunction _removeFromIndex( collection, toRemove, unset : boolean ){\n var removed = Array( toRemove.length ),\n _byId = collection._byId;\n\n for( var i = 0, j = 0; i < toRemove.length; i++ ){\n var model = collection.get( toRemove[ i ] );\n if( model ){\n removed[ j++ ] = model;\n removeIndex( _byId, model );\n free( collection, model, unset );\n }\n }\n\n removed.length = j;\n\n return removed;\n}\n\n// Allocate new models array removing models not present in the index.\n/** @private */\nfunction _reallocate( collection, removed ){\n var prev = collection.models,\n models = collection.models = Array( prev.length - removed ),\n _byId = collection._byId;\n\n for( var i = 0, j = 0; i < prev.length; i++ ){\n var model = prev[ i ];\n\n if( _byId[ model.cid ] ){\n models[ j++ ] = model;\n }\n }\n\n models.length = j;\n}","import { Record } from '../record';\nimport { Transaction, transactionApi } from '../transactions';\nimport { addIndex, CollectionCore, CollectionOptions, CollectionTransaction, convertAndAquire, Elements, free, freeAll, IdIndex, logAggregationError, sortElements } from './commons';\n\nconst { begin, commit, markAsDirty } = transactionApi;\n\n/** @private */\nconst silentOptions = { silent : true };\n\n/** @private */\nexport function emptySetTransaction( collection : CollectionCore, items : Elements, options : CollectionOptions, silent? : boolean ){\n const isRoot = begin( collection );\n\n const added = _reallocateEmpty( collection, items, options );\n\n if( added.length ){\n const needSort = sortElements( collection, options );\n\n if( markAsDirty( collection, silent ? silentOptions : options ) ){\n // 'added' is the reference to this.models. Need to copy it.\n return new CollectionTransaction( collection, isRoot, added.slice(), [], [], needSort );\n }\n\n if( collection._aggregationError ) logAggregationError( collection, options );\n }\n\n // No changes...\n isRoot && commit( collection );\n};\n\n/** @private */\nexport function setTransaction( collection, items, options ){\n const isRoot = begin( collection ),\n nested = [];\n\n var previous = collection.models,\n added = _reallocate( collection, items, nested, options );\n\n const reusedCount = collection.models.length - added.length,\n removed = reusedCount < previous.length ? (\n reusedCount ? _garbageCollect( collection, previous ) :\n freeAll( collection, previous )\n ) : []; \n \n const addedOrChanged = nested.length || added.length,\n // As we are reallocating models array, it needs to be sorted even if there are no changes.\n sorted = ( sortElements( collection, options ) && addedOrChanged ) || added.length || options.sorted;\n\n if( addedOrChanged || removed.length || sorted ){\n if( markAsDirty( collection, options ) ){ \n return new CollectionTransaction( collection, isRoot, added, removed, nested, sorted );\n }\n\n if( collection._aggregationError ) logAggregationError( collection, options );\n }\n\n isRoot && commit( collection );\n};\n\n// Remove references to all previous elements, which are not present in collection.\n// Returns an array with removed elements.\n/** @private */\nfunction _garbageCollect( collection : CollectionCore, previous : Record[] ) : Record[]{\n const { _byId } = collection,\n removed = [];\n\n // Filter out removed models and remove them from the index...\n for( let record of previous ){\n if( !_byId[ record.cid ] ){\n removed.push( record );\n free( collection, record );\n }\n }\n\n return removed;\n}\n\n// reallocate model and index\n/** @private */\nfunction _reallocate( collection : CollectionCore, source : any[], nested : Transaction[], options ){\n var models = Array( source.length ),\n _byId : IdIndex = {},\n merge = ( options.merge == null ? true : options.merge ) && !collection._shared,\n _prevById = collection._byId,\n prevModels = collection.models, \n idAttribute = collection.model.prototype.idAttribute,\n toAdd = [],\n orderKept = true;\n\n // for each item in source set...\n for( var i = 0, j = 0; i < source.length; i++ ){\n var item = source[ i ],\n model : Record = null;\n\n if( item ){\n var id = item[ idAttribute ],\n cid = item.cid;\n\n if( _byId[ id ] || _byId[ cid ] ) continue;\n\n model = _prevById[ id ] || _prevById[ cid ];\n }\n\n if( model ){\n if( merge && item !== model ){\n if( orderKept && prevModels[ j ] !== model ) orderKept = false;\n\n var attrs = item.attributes || item;\n const transaction = model._createTransaction( attrs, options );\n transaction && nested.push( transaction );\n }\n }\n else{\n model = convertAndAquire( collection, item, options );\n toAdd.push( model );\n }\n\n models[ j++ ] = model;\n addIndex( _byId, model );\n }\n\n models.length = j;\n collection.models = models;\n collection._byId = _byId;\n\n if( !orderKept ) options.sorted = true;\n\n return toAdd;\n}\n\n/** @private */\nfunction _reallocateEmpty( self, source, options ){\n var len = source ? source.length : 0,\n models = Array( len ),\n _byId : IdIndex = {},\n idAttribute = self.model.prototype.idAttribute;\n\n for( var i = 0, j = 0; i < len; i++ ){\n var src = source[ i ];\n\n if( src && ( _byId[ src[ idAttribute ] ] || _byId[ src.cid ] ) ){\n continue;\n }\n\n var model = convertAndAquire( self, src, options );\n models[ j++ ] = model;\n addIndex( _byId, model );\n }\n\n models.length = j;\n self._byId = _byId;\n\n return self.models = models;\n}","import { Record } from '../record'\n\nexport type Predicate = ( ( val : R, key? : number ) => boolean ) | Partial;\n\n/**\n * Optimized array methods.\n */\nexport abstract class ArrayMixin {\n models : R[]\n abstract get( modelOrId : string | Partial ) : R;\n\n /**\n * Map and optionally filter the collection.\n * @param mapFilter filter an element out if `undefined` is returned \n * @param context optional `this` for `mapFilter`\n */\n map( mapFilter : ( val : R, key? : number ) => T, context? : any ) : T[]{\n const { models } = this,\n { length } = models,\n res = Array( length ),\n fun = context ? mapFilter.bind( context ) : mapFilter;\n\n for( var i = 0, j = 0; i < length; i++ ){\n const val = fun( models[ i ], i );\n val === void 0 || ( res[ j++ ] = val );\n }\n\n if( i !== j ){\n res.length = j;\n }\n\n return res;\n }\n\n /**\n * Iterate through the collection.\n * @param context optional `this` for `iteratee`.\n */\n each( fun : ( val : R, key? : number ) => any, context? : any ) : void {\n const { models } = this,\n { length } = models,\n iteratee = context ? fun.bind( context ) : fun;\n\n for( let i = 0; i < length; i++ ){\n iteratee( models[ i ], i );\n }\n }\n\n /**\n * Iterate through collection optionally returning the value.\n * @param doWhile break the loop if anything but `undefined` is returned, and return this value.\n * @param context optional `this` for `doWhile`.\n */\n firstMatch( doWhile : ( val : R, key? : number ) => T ) : T\n firstMatch( doWhile : ( this : C, val : R, key? : number ) => T, context : C ) : T\n firstMatch( doWhile : ( val : R, key? : number ) => T, context? : any ) : T {\n const { models } = this,\n { length } = models,\n iteratee = context ? doWhile.bind( context ) : doWhile;\n\n for( let i = 0; i < length; i++ ){\n const res = iteratee( models[ i ], i );\n if( res !== void 0 ) return res;\n }\n }\n\n /**\n * Proxy for the `array.reduce()`\n * @param iteratee \n */\n reduce( iteratee : (previousValue: R, currentValue: R, currentIndex?: number ) => R ) : R\n reduce( iteratee : (previousValue: T, currentValue: R, currentIndex?: number ) => T, init? : any ) : T\n reduce( iteratee : (previousValue: any, currentValue: any, currentIndex?: number ) => any, init? : any ) : T | R {\n return init === void 0 ? this.models.reduce( iteratee ) : this.models.reduce( iteratee, init );\n }\n\n // Slice out a sub-array of models from the collection.\n slice( begin? : number, end? : number ) : R[] {\n return this.models.slice( begin, end );\n }\n \n indexOf( modelOrId : string | Partial ) : number {\n return this.models.indexOf( this.get( modelOrId ) );\n }\n\n includes( idOrObj : string | Partial ) : boolean {\n return Boolean( this.get( idOrObj ) );\n }\n\n filter( iteratee : Predicate, context? : any ) : R[] {\n const fun = toPredicateFunction( iteratee );\n return this.map( m => fun( m ) ? m : void 0, context );\n }\n\n find( iteratee : Predicate, context? : any ) : R {\n const fun = toPredicateFunction( iteratee );\n return this.firstMatch( m => fun( m ) ? m : void 0, context );\n }\n\n some( iteratee : Predicate, context? : any ) : boolean {\n return Boolean( this.find( iteratee, context ) );\n }\n\n forEach( iteratee : ( val : R, key? : number ) => void, context? : any ) : void {\n this.each( iteratee, context );\n }\n\n values() : IterableIterator {\n return this.models.values();\n }\n\n entries() : IterableIterator<[ number, R ]>{\n return this.models.entries();\n }\n\n every( iteratee : Predicate, context? : any ) : boolean {\n const fun = toPredicateFunction( iteratee );\n return this.firstMatch( m => fun( m ) ? void 0 : false, context ) === void 0;\n }\n\n pluck( key : K ) : R[K][] {\n return this.map( model => model[ key ] );\n }\n\n first() : R { return this.models[ 0 ]; }\n\n last() : R { return this.models[ this.models.length - 1 ]; }\n\n at( a_index : number ) : R {\n const index = a_index < 0 ? a_index + this.models.length : a_index; \n return this.models[ index ];\n }\n}\n\nconst noOp = x => x;\n\nfunction toPredicateFunction( iteratee : Predicate ){\n if( iteratee == null ) return noOp;\n\n switch( typeof iteratee ){\n case 'function' : return iteratee;\n case 'object' :\n const keys = Object.keys( iteratee );\n \n return x => {\n for( let key of keys ){\n if( iteratee[ key ] !== x[ key ] )\n return false;\n }\n\n return true;\n }\n default : throw new Error( 'Invalid iteratee' );\n }\n}","import { IOPromise, startIO } from '../io-tools';\nimport { define, definitions, EventMap, eventsApi, EventsDefinition, Logger, logger, LogLevel, Mixable, mixinRules, TheType, tools, mixins } from '../object-plus';\nimport { AggregatedType, Record, SharedType } from '../record';\nimport { CloneOptions, ItemsBehavior, Transactional, TransactionalDefinition, transactionApi, TransactionOptions } from '../transactions';\nimport { AddOptions, addTransaction } from './add';\nimport { CollectionCore, CollectionTransaction, Elements, free, sortElements, updateIndex } from './commons';\nimport { removeMany, removeOne } from './remove';\nimport { emptySetTransaction, setTransaction } from './set';\n\nconst { trigger2 } = eventsApi,\n { begin, commit, markAsDirty } = transactionApi;\n\nlet _count = 0;\n\nexport type GenericComparator = string | ( ( x : Record ) => number ) | ( ( a : Record, b : Record ) => number ); \n\nexport interface CollectionOptions extends TransactionOptions {\n comparator? : GenericComparator\n model? : typeof Record\n}\n\nexport interface CollectionDefinition extends TransactionalDefinition {\n model? : typeof Record,\n itemEvents? : EventsDefinition\n _itemEvents? : EventMap\n}\n\nclass CollectionRefsType extends SharedType {\n static defaultValue = [];\n}\n\nexport interface CollectionConstructor extends TheType {\n new ( records? : ElementsArg, options?: CollectionOptions ) : Collection\n prototype : Collection\n Refs : CollectionConstructor\n};\n\n@define({\n // Default client id prefix \n cidPrefix : 'c',\n model : Record,\n _changeEventName : 'changes',\n _aggregationError : null\n})\n@mixins( ArrayMixin )\n@definitions({\n comparator : mixinRules.value,\n model : mixinRules.protoValue,\n itemEvents : mixinRules.merge\n})\nexport class Collection< R extends Record = Record> extends Transactional implements CollectionCore, Iterable {\n /** @internal */\n _shared : number\n /** @internal */\n _aggregationError : R[]\n\n /**\n * EXPERIMENTAL notation to extract proper collection type from the model in TypeScript.\n * \n * attrName : Collection.of( User );\n * \n * const users = new ( Collection.of( User ) )\n */\n static of( Ctor : M ) : M['Collection'] extends CollectionConstructor> ? M['Collection'] : CollectionConstructor> {\n return Ctor.Collection as any;\n }\n\n /**\n * EXPERIMENTAL notation to extract proper collection type from the model in TypeScript.\n * \n * attrName : Collection.ofRefs( User );\n * \n * const users = new ( Collection.ofRefs( User ) )\n */\n static ofRefs( Ctor : M ) : M['Collection'] extends CollectionConstructor> ? M['Collection'] : CollectionConstructor> {\n return Ctor.Collection.Refs as any;\n }\n\n static Subset : typeof Collection\n static Refs : any\n\n /** @internal */\n static _SubsetOf : typeof Collection\n \n createSubset( models : ElementsArg, options? : CollectionOptions) : Collection{\n throw new ReferenceError( 'Failed dependency injection' )\n }\n\n static onExtend( BaseClass : typeof Transactional ){\n // Cached subset collection must not be inherited.\n const Ctor = this;\n this._SubsetOf = null;\n\n function RefsCollection( a, b, listen? ){\n Ctor.call( this, a, b, ItemsBehavior.share | ( listen ? ItemsBehavior.listen : 0 ) );\n }\n\n Mixable.mixins.populate( RefsCollection );\n \n RefsCollection.prototype = this.prototype;\n RefsCollection._metatype = CollectionRefsType;\n\n this.Refs = this.Subset = RefsCollection;\n\n Transactional.onExtend.call( this, BaseClass );\n }\n \n static onDefine( definition : CollectionDefinition, BaseClass : any ){\n if( definition.itemEvents ){\n const eventsMap = new EventMap( BaseClass.prototype._itemEvents );\n eventsMap.addEventsMap( definition.itemEvents );\n this.prototype._itemEvents = eventsMap;\n }\n\n if( definition.comparator !== void 0 ) this.prototype.comparator = definition.comparator;\n\n Transactional.onDefine.call( this, definition );\n }\n \n /** @internal */\n _itemEvents : EventMap\n\n /***********************************\n * Core Members\n */\n // Array of the records\n models : R[]\n\n // Polymorphic accessor for aggregated attribute's canBeUpdated().\n /** @internal */\n get __inner_state__(){ return this.models; }\n\n // Index by id and cid\n /** @internal */\n _byId : { [ id : string ] : R }\n\n set comparator( x : GenericComparator ){\n\n switch( typeof x ){\n case 'string' :\n this._comparator = ( a, b ) => {\n const aa = a[ x ], bb = b[ x ];\n if( aa === bb ) return 0;\n return aa < bb ? -1 : + 1;\n } \n break;\n case 'function' :\n if( x.length === 1 ){\n this._comparator = ( a, b ) => {\n const aa = (x).call( this, a ), bb = (x).call( this, b );\n if( aa === bb ) return 0;\n return aa < bb ? -1 : + 1;\n }\n }\n else{\n this._comparator = ( a, b ) => (x).call( this, a, b );\n }\n break;\n \n default :\n this._comparator = null;\n }\n }\n \n // TODO: Improve typing\n getStore() : Transactional {\n return this._store || ( this._store = this._owner ? this._owner.getStore() : this._defaultStore );\n }\n\n /** @internal */\n _store : Transactional\n\n get comparator(){ return this._comparator; }\n\n /** @internal */\n _comparator : ( a : R, b : R ) => number\n\n /** @internal */\n _onChildrenChange( record : R, options : TransactionOptions = {}, initiator? : Transactional ){\n // Ignore updates from nested transactions.\n if( initiator === this ) return;\n\n const { idAttribute } = this;\n\n if( record.hasChanged( idAttribute ) ){\n updateIndex( this._byId, record );\n }\n\n const isRoot = begin( this );\n\n if( markAsDirty( this, options ) ){\n // Forward change event from the record.\n trigger2( this, 'change', record, options )\n }\n\n isRoot && commit( this );\n }\n\n get( objOrId : string | { id? : string, cid? : string } ) : R {\n if( objOrId == null ) return;\n\n if( typeof objOrId === 'object' ){\n const id = objOrId[ this.idAttribute ];\n return ( id !== void 0 && this._byId[ id ] ) || this._byId[ objOrId.cid ];\n }\n else{\n return this._byId[ objOrId ];\n } \n }\n\n [ Symbol.iterator ]() : IterableIterator {\n return this.models[ Symbol.iterator ]();\n }\n\n // Loop through the members in the scope of transaction.\n // Transactional version of each()\n updateEach( iteratee : ( val : R, key? : number ) => void ){\n const isRoot = transactionApi.begin( this );\n this.each( iteratee );\n isRoot && transactionApi.commit( this );\n }\n\n /** @internal */\n _validateNested( errors : {} ) : number {\n // Don't validate if not aggregated.\n if( this._shared ) return 0;\n\n let count = 0;\n\n this.each( record => {\n const error = record.validationError;\n if( error ){\n errors[ record.cid ] = error;\n count++;\n }\n });\n\n return count;\n }\n\n model : typeof Record\n\n // idAttribute extracted from the model type.\n idAttribute : string\n\n constructor( records? : ElementsArg, options : CollectionOptions = {}, shared? : number ){\n super( _count++ );\n this.models = [];\n this._byId = {};\n \n this.comparator = this.comparator;\n\n if( options.comparator !== void 0 ){\n this.comparator = options.comparator;\n options.comparator = void 0;\n }\n \n this.model = this.model;\n \n if( options.model ){\n this.model = options.model;\n options.model = void 0;\n }\n\n this.idAttribute = this.model.prototype.idAttribute; //TODO: Remove?\n\n this._shared = shared || 0;\n\n if( records ){\n const elements = toElements( this, records, options );\n emptySetTransaction( this, elements, options, true );\n }\n\n this.initialize.apply( this, arguments );\n\n if( this._localEvents ) this._localEvents.subscribe( this, this );\n }\n\n initialize(){}\n\n // Deeply clone collection, optionally setting new owner.\n clone( options : CloneOptions = {} ) : this {\n const models = this._shared & ItemsBehavior.share ? this.models : this.map( model => model.clone() ),\n copy : this = new (this.constructor)( models, { model : this.model, comparator : this.comparator }, this._shared );\n \n if( options.pinStore ) copy._defaultStore = this.getStore();\n \n return copy;\n }\n\n toJSON( options? : object ) : any {\n return this.map( model => model.toJSON( options ) );\n }\n\n // Apply bulk in-place object update in scope of ad-hoc transaction \n set( elements : ElementsArg = [], options : TransactionOptions = {} ) : this {\n if( (options).add !== void 0 ){\n this._log( 'warn', \"Type-R:InvalidOption\", \"Collection.set doesn't support 'add' option, behaving as if options.add === true.\", options );\n }\n\n // Handle reset option here - no way it will be populated from the top as nested transaction.\n if( options.reset ){\n this.reset( elements, options )\n }\n else{\n const transaction = this._createTransaction( elements, options );\n transaction && transaction.commit();\n } \n\n return this; \n }\n\n /**\n * Enable or disable live updates.\n * \n * `true` enables full collection synchronization.\n * `false` cancel live updates.\n * `json => true | false` - filter updates\n */\n liveUpdates( enabled : LiveUpdatesOption ) : IOPromise {\n if( enabled ){\n this.liveUpdates( false );\n\n const filter = typeof enabled === 'function' ? enabled : () => true;\n\n this._liveUpdates = {\n updated : json => {\n filter( json ) && this.add( json, { parse : true, merge : true } );\n },\n\n removed : id => this.remove( id )\n };\n\n return this.getEndpoint().subscribe( this._liveUpdates, this ).then( () => this );\n }\n else{\n if( this._liveUpdates ){\n this.getEndpoint().unsubscribe( this._liveUpdates, this );\n this._liveUpdates = null;\n }\n\n // TODO: Return the resolved promise.\n }\n }\n\n /** @internal */\n _liveUpdates : object\n\n fetch( a_options : { liveUpdates? : LiveUpdatesOption } & TransactionOptions = {} ) : IOPromise {\n const options = { parse : true, ...a_options },\n endpoint = this.getEndpoint();\n\n return startIO(\n this,\n endpoint.list( options, this ),\n options,\n\n json => {\n let result : any = this.set( json, { parse : true, ioMethod : 'fetch', ...options } as TransactionOptions );\n \n if( options.liveUpdates ){\n result = this.liveUpdates( options.liveUpdates );\n }\n\n return result;\n }\n );\n }\n\n dispose() : void {\n if( this._disposed ) return;\n\n const aggregated = !this._shared;\n\n for( let record of this.models ){\n free( this, record );\n\n if( aggregated ) record.dispose();\n }\n\n this.liveUpdates( false );\n\n super.dispose();\n }\n\n reset( a_elements? : ElementsArg, options : TransactionOptions = {} ) : R[] {\n const isRoot = begin( this ),\n previousModels = this.models;\n\n // Make all changes required, but be silent.\n if( a_elements ){ \n emptySetTransaction( this, toElements( this, a_elements, options ), options, true );\n }\n else{\n this._byId = {};\n this.models = [];\n }\n\n markAsDirty( this, options );\n\n options.silent || trigger2( this, 'reset', this, { previousModels, ...options } );\n\n // Dispose models which are not in the updated collection.\n const { _byId } = this;\n \n for( let toDispose of previousModels ){\n _byId[ toDispose.cid ] || free( this, toDispose );\n }\n\n isRoot && commit( this );\n return this.models;\n }\n\n // Add elements to collection.\n add( a_elements : ElementsArg , options : AddOptions = {} ){\n const elements = toElements( this, a_elements, options ),\n transaction = this.models.length ?\n addTransaction( this, elements, options ) :\n emptySetTransaction( this, elements, options );\n\n if( transaction ){\n transaction.commit();\n return transaction.added;\n }\n }\n\n // Remove elements. \n remove( recordsOrIds : any, options : CollectionOptions = {} ) : R[] | R {\n if( recordsOrIds ){\n return Array.isArray( recordsOrIds ) ?\n removeMany( this, recordsOrIds, options ) as R[]:\n removeOne( this, recordsOrIds, options ) as R;\n }\n\n return [];\n }\n\n // Apply bulk object update without any notifications, and return open transaction.\n // Used internally to implement two-phase commit. \n /** @internal */\n _createTransaction( a_elements : ElementsArg, options : TransactionOptions = {} ) : CollectionTransaction | void {\n const elements = toElements( this, a_elements, options );\n\n if( this.models.length ){\n return options.remove === false ?\n addTransaction( this, elements, options, true ) :\n setTransaction( this, elements, options );\n }\n else{\n return emptySetTransaction( this, elements, options );\n }\n }\n\n /** @internal */\n static _metatype = AggregatedType;\n\n /***********************************\n * Collection manipulation methods\n */\n\n sort( options : TransactionOptions = {} ) : this {\n if( sortElements( this, options ) ){\n const isRoot = begin( this );\n \n if( markAsDirty( this, options ) ){\n trigger2( this, 'sort', this, options );\n }\n\n isRoot && commit( this );\n }\n\n return this;\n }\n\n // Remove and return given model.\n unset( modelOrId : R | string, options? ) : R {\n const value = this.get( modelOrId );\n this.remove( modelOrId, { unset : true, ...options } );\n return value;\n }\n\n modelId( attrs : {} ) : any {\n return attrs[ this.model.prototype.idAttribute ];\n }\n\n // Toggle model in collection.\n toggle( model : R, a_next? : boolean ) : boolean {\n var prev = Boolean( this.get( model ) ),\n next = a_next === void 0 ? !prev : Boolean( a_next );\n\n if( prev !== next ){\n if( prev ){\n this.remove( model );\n }\n else{\n this.add( model );\n }\n }\n\n return next;\n }\n\n /** @internal */\n _log( level : LogLevel, topic : string, text : string, value : object, a_logger? : Logger ) : void {\n ( a_logger || logger ).trigger( level, topic, `${ this.model.prototype.getClassName() }.${ this.getClassName() }: ` + text, {\n Argument : value,\n 'Attributes spec' : this.model.prototype._attributes\n });\n }\n\n getClassName() : string {\n return super.getClassName() || 'Collection';\n }\n\n /***********************************\n * Proxied Array methods\n */\n\n get length() : number { return this.models.length; }\n\n // Add a model to the end of the collection.\n push(model : ElementsArg, options? : CollectionOptions ) {\n return this.add(model, { at: this.length, ...options });\n }\n\n // Remove a model from the end of the collection.\n pop( options? : CollectionOptions ) : R {\n var model = this.at(this.length - 1);\n this.remove(model, { unset : true, ...options });\n return model;\n }\n\n // Add a model to the beginning of the collection.\n unshift(model : ElementsArg, options? : CollectionOptions ) {\n return this.add(model, { at: 0, ...options });\n }\n \n // Remove a model from the beginning of the collection.\n shift( options? : CollectionOptions ) : R {\n const model = this.at(0);\n this.remove( model, { unset : true, ...options } );\n return model;\n }\n}\n\nimport { ArrayMixin } from './arrayMethods'\n\nexport interface Collection extends ArrayMixin{}\n\nexport type LiveUpdatesOption = boolean | ( ( x : any ) => boolean );\n\nexport type ElementsArg = Partial | Partial[]\n\n// TODO: make is safe for parse to return null (?)\nfunction toElements( collection : Collection, elements : ElementsArg, options : CollectionOptions ) : Elements {\n const parsed = options.parse ? collection.parse( elements, options ) : elements; \n return Array.isArray( parsed ) ? parsed : [ parsed ];\n}\n\nRecord.Collection = Collection;","import { Collection } from '../collection';\nimport { Record } from '../record';\nimport { CompiledReference } from '../traversable';\n\nexport type CollectionReference = ( () => Collection ) | Collection | string; \n\n/** @private */\nexport function parseReference( collectionRef : CollectionReference ) : ( root : Record ) => Collection {\n switch( typeof collectionRef ){\n case 'function' :\n return root => (collectionRef).call( root );\n case 'object' :\n return () => collectionRef;\n case 'string' :\n const { resolve } = new CompiledReference( collectionRef );\n return resolve;\n }\n}","import { AnyType, ChainableAttributeSpec, Record } from '../record';\nimport { CollectionReference, parseReference } from './commons';\n\n\n/********\n * Reference to model by id.\n * \n * Untyped attribute. Holds model id, when unresolved. When resolved, is substituted\n * with a real model.\n * \n * No model changes are detected and counted as owner's change. That's intentional.\n */\n\n/** @private */\ntype RecordRefValue = Record | string;\n\n/** @private */\nclass RecordRefType extends AnyType {\n // It is always serialized as an id, whenever it's resolved or not. \n toJSON( value : RecordRefValue ){\n return value && typeof value === 'object' ? value.id : value;\n }\n\n // Wne \n clone( value : RecordRefValue ){\n return value && typeof value === 'object' ? value.id : value;\n }\n\n // Model refs by id are equal when their ids are equal.\n isChanged( a : RecordRefValue, b : RecordRefValue){\n var aId = a && ( (a).id == null ? a : (a).id ),\n bId = b && ( (b).id == null ? b : (b).id );\n\n return aId !== bId;\n }\n\n // Refs are always valid.\n validate( model, value, name ){}\n}\n\nexport function memberOf( this : void, masterCollection : CollectionReference, T? : R ) : ChainableAttributeSpec {\n const getMasterCollection = parseReference( masterCollection );\n\n const typeSpec = new ChainableAttributeSpec({\n value : null,\n _metatype : RecordRefType\n });\n \n return typeSpec\n .get( function( objOrId : RecordRefValue, name : string ) : Record {\n if( typeof objOrId === 'object' ) return objOrId;\n\n // So, we're dealing with an id reference. Resolve it.\n const collection = getMasterCollection( this );\n let record : Record = null;\n\n // If master collection exists and is not empty...\n if( collection && collection.length ){\n // Silently update attribute with record from this collection.\n record = collection.get( objOrId ) || null;\n this.attributes[ name ] = record;\n\n // Subscribe for events manually. delegateEvents won't be invoked.\n record && this._attributes[ name ].handleChange( record, null, this, {} );\n }\n\n return record;\n });\n}","import { Collection, CollectionConstructor } from '../collection';\nimport { define, tools } from '../object-plus';\nimport { AggregatedType, ChainableAttributeSpec, Record, type } from '../record';\nimport { ItemsBehavior, transactionApi } from '../transactions';\nimport { CollectionReference, parseReference } from './commons';\n\n\ntype RecordsIds = ( string | number )[];\n\nexport function subsetOf, R extends Record>( this : void, masterCollection : CollectionReference, T? : X ) : ChainableAttributeSpec{\n const CollectionClass = T || Collection,\n // Lazily define class for subset collection, if it's not defined already...\n SubsetOf = CollectionClass._SubsetOf || ( CollectionClass._SubsetOf = defineSubsetCollection( CollectionClass as any ) as any ),\n getMasterCollection = parseReference( masterCollection );\n\n return type( SubsetOf ).get(\n function( refs ){\n !refs || refs.resolvedWith || refs.resolve( getMasterCollection( this ) );\n return refs;\n }\n );\n}\n\nCollection.prototype.createSubset = function( models : any, options ) : Collection {\n const SubsetOf = subsetOf( this, this.constructor ).options.type,\n subset = new SubsetOf( models, options );\n \n subset.resolve( this );\n return subset;\n}\n\nconst subsetOfBehavior = ItemsBehavior.share | ItemsBehavior.persistent;\n\nfunction defineSubsetCollection( CollectionClass : typeof Collection ) {\n @define class SubsetOfCollection extends CollectionClass {\n refs : any[];\n resolvedWith : Collection = null;\n\n _metatype : AggregatedType\n\n get __inner_state__(){ return this.refs || this.models; }\n\n constructor( recordsOrIds?, options? ){\n super( [], options, subsetOfBehavior );\n this.refs = toArray( recordsOrIds );\n }\n\n // Remove should work fine as it already accepts ids. Add won't...\n add( a_elements, options = {} ){\n const { resolvedWith } = this,\n toAdd = toArray( a_elements );\n \n if( resolvedWith ){\n // If the collection is resolved already, everything is simple.\n return super.add( resolveRefs( resolvedWith, toAdd ), options );\n }\n else{\n // Collection is not resolved yet. So, we prepare the delayed computation.\n if( toAdd.length ){\n const isRoot = transactionApi.begin( this );\n\n // Save elements to resolve in future...\n this.refs = this.refs ? this.refs.concat( toAdd ) : toAdd.slice();\n\n transactionApi.markAsDirty( this, options );\n\n // And throw the 'changes' event.\n isRoot && transactionApi.commit( this );\n }\n }\n }\n\n reset( a_elements?, options = {} ){\n const { resolvedWith } = this,\n elements = toArray( a_elements );\n \n return resolvedWith ?\n // Collection is resolved, so parse ids and forward the call to set.\n super.reset( resolveRefs( resolvedWith, elements ), options ) :\n // Collection is not resolved yet. So, we prepare the delayed computation.\n delaySet( this, elements, options ) as any || [];\n }\n\n _createTransaction( a_elements, options? ){\n const { resolvedWith } = this,\n elements = toArray( a_elements );\n \n return resolvedWith ?\n // Collection is resolved, so parse ids and forward the call to set.\n super._createTransaction( resolveRefs( resolvedWith, elements ), options ) :\n // Collection is not resolved yet. So, we prepare the delayed computation.\n delaySet( this, elements, options );\n }\n\n // Serialized as an array of model ids.\n toJSON() : RecordsIds {\n return this.refs ?\n this.refs.map( objOrId => objOrId.id || objOrId ) :\n this.models.map( model => model.id );\n }\n\n // Subset is always valid.\n _validateNested(){ return 0; }\n\n get length() : number {\n return this.models.length || ( this.refs ? this.refs.length : 0 );\n }\n\n // Must be shallow copied on clone.\n clone( owner? ){\n var Ctor = (this).constructor,\n copy = new Ctor( [], {\n model : this.model,\n comparator : this.comparator\n });\n\n if( this.resolvedWith ){\n // TODO: bug here. \n copy.resolvedWith = this.resolvedWith;\n copy.refs = null;\n copy.reset( this.models, { silent : true } );\n }\n else{\n copy.refs = this.refs.slice();\n }\n\n return copy;\n }\n\n // Clean up the custom parse method possibly defined in the base class.\n parse( raw : any ) : Record[] {\n return raw;\n }\n\n resolve( collection : Collection ) : this {\n if( collection && collection.length ){\n this.resolvedWith = collection;\n\n if( this.refs ){\n this.reset( this.refs, { silent : true } );\n this.refs = null;\n }\n }\n\n return this;\n }\n\n getModelIds() : RecordsIds { return this.toJSON(); }\n\n toggle( modelOrId : any, val : boolean ) : boolean {\n return super.toggle( this.resolvedWith.get( modelOrId ), val );\n }\n\n addAll() : Record[] {\n if( this.resolvedWith ){\n this.set( this.resolvedWith.models );\n return this.models;\n }\n\n throw new Error( \"Cannot add elemens because the subset collection is not resolved yet.\" );\n }\n\n toggleAll() : Record[] {\n return this.length ? this.reset() : this.addAll();\n }\n }\n\n // Clean up all custom item events to prevent memory leaks.\n SubsetOfCollection.prototype._itemEvents = void 0;\n\n return SubsetOfCollection;\n}\n\nfunction resolveRefs( master, elements ){\n const records = [];\n \n for( let el of elements ){\n const record = master.get( el );\n if( record ) records.push( record );\n }\n\n return records;\n}\n\nfunction delaySet( collection, elements, options ) : void {\n if( tools.notEqual( collection.refs, elements ) ){\n const isRoot = transactionApi.begin( collection );\n\n // Save elements to resolve in future...\n collection.refs = elements.slice();\n\n transactionApi.markAsDirty( collection, options );\n \n // And throw the 'changes' event.\n isRoot && transactionApi.commit( collection );\n }\n}\n\nfunction toArray( elements ){\n return elements ? ( \n Array.isArray( elements ) ? elements : [ elements ]\n ) : [];\n}","import { Record } from '../record';\nimport { Transactional } from '../transactions';\n\nlet _store : Store = null;\n\nexport class Store extends Record {\n getStore() : Store { return this; }\n \n // delegate item lookup to owner, and to the global store if undefined\n get( name : string ) : any {\n // Lookup for resource in the current store. \n let local = this[ name ];\n\n // If something is found or it's the global store, return result.\n if( local || this === this._defaultStore ) return local;\n\n // Forward failed lookup to owner or global store.\n return this._owner ? this._owner.get( name ) : this._defaultStore.get( name ); \n }\n\n static get global(){ return _store; }\n static set global( store : Store ){\n if( _store ){\n _store.dispose();\n }\n\n Transactional.prototype._defaultStore = _store = store;\n }\n}\n\nStore.global = new Store();","// Dummy polyfill to prevent exception in IE.\nif( typeof Symbol === 'undefined' ){\n Object.defineProperty( window, 'Symbol', { value : { iterator : 'Symbol.iterator' }, configurable : true });\n}\n\nimport { Events, Mixable as Class } from './object-plus/';\n// Define synonims for NestedTypes backward compatibility.\nimport { Record as Model } from './record';\n\n/**\n * Export everything \n */\nexport * from './collection';\nexport * from './io-tools';\nexport * from './object-plus';\nexport * from './record';\nexport * from './relations';\nexport * from './transactions';\nexport { Model, Class };\n\n\nexport const { on, off, trigger, once, listenTo, stopListening, listenToOnce } = Events;\n\n/** Wrap model or collection method in transaction. */\nexport function transaction< F extends Function >( method : F ) : F {\n return function( ...args ){\n let result;\n \n this.transaction( () => {\n result = method.apply( this, args );\n });\n \n return result;\n }\n}"],"names":["defaults","dest","source","name","hasOwnProperty","arguments","length","i","other","isValidJSON","value","proto","Object","getPrototypeOf","prototype","Array","every","getBaseClass","Class","constructor","isEmpty","obj","key","some","fun","ArrayProto","arr","result","someArray","someObject","predicate","x","omit","discard","transform","assign","once","func","memo","first","apply","this","DateProto","Date","ObjectProto","notEqual","a","b","protoA","arraysNotEqual","keysA","keys","objectsNotEqual","HashProto","create","hashMap","hash","definition","_i","names","names_1","_a","name_1","prop","desc","getOwnPropertyDescriptor","o","map","EventMap","handlers","slice","addEventsMap","concat","addEvent","split","eventSplitter","getBubblingHandler","callback","name_2","push","EventDescriptor","target","event_1","on","event_2","off","handler","_bubblingHandlers","event","c","d","e","trigger5","trigger3","trigger2","context","next","listOff","_events","filteredHead","prev","head","ev","_callback","listSend3","call","EventHandler","once_1","_once","name_3","strings","api","events","test","self","queue","all","listSend2","listSend4","listSend5","f","listSend6","extendStatics","setPrototypeOf","__proto__","p","__extends","__","__assign","t","s","n","__rest","indexOf","getOwnPropertySymbols","__decorate","decorators","r","Reflect","decorate","defineProperty","Mixable","protoProps","staticProps","BaseClass","mixins","defineMixin","merge","mergeObject","getStaticDefinitions","onDefine","definitions","mergeInheritedMembers","spec","statics","TheSubclass","tslib_1.__extends","predefine","define","Constructor","__super__","MixinsState","get","populate","onExtend","ClassOrDefinition","Ctor","rules","definitionRules","definitionDecorator","definitionKey","mergeRules","appliedMixins","rule","mixins_1","mixin","isArray","sourceMixins","ctors","ctors_1","unshift","object","ignore","dontMix","getOwnPropertyNames","forEachOwnProp","sourceProp","_this","assignProperty","mixinRules","protoValue","baseProto","resolveRule","function","caller","list","destProp","configurable","pipe","classFirst","classLast","_idCount","uniqueId","cid","initialize","Messenger","localEvents","_localEvents","properties","eventsMap","defineProperties","toPropertyDescriptor","addReference","a_source","_listeningTo","removeAll","second","_disposed","stopListening","Events","listener","isProduction","process","env","NODE_ENV","logEvents","Logger","level","filter","topic","msg","props","args","toString","console","Error","counter","_super","window","something","body","join","JSON","stringify","logger","logEvents_1","logToConsole","throwingLogger","throwOn","log","trigger","bind","startIO","promise","options","thenDo","abortIO","_ioPromise","then","resp","triggerAndBubble","catch","err","abort","eventSource","collection","referenceMask","reference","splitTail","path","match","substr","tail","pop","local","resolve","Function","shift","resolveReference","root","action","skip","getStore","getOwner","ItemsBehavior","_validateNested","nested","error","validate","ValidationError","iteratee","each","eachError","cidPrefix","Transactional","endpoint","_endpoint","Transactional_1","_owner","_ownerKey","_changeEventName","listenTo","isRoot","transactionApi","begin","update","set","commit","transaction","__inner_state__","_changeToken","json","strict","validationError","eachValidationError","getClassName","data","_defaultStore","getOwnerEndpoint","_endpoints","_validationError","getValidationError","_transaction","markAsDirty","dirty","silent","_isDirty","initiator","originalOptions","_onChildrenChange","aquire","owner","child","ReferenceError","free","_begin","_markAsDirty","setAttribute","record","_attributes","doUpdate","attributes","_previousAttributes","AttributesCopy","_changedAttributes","UpdateRecordMixin","attribute","propagateChanges","forceAttributeChange","_createTransaction","a_values","unknown","changes","values","parse","shouldBeAnObject","unknownAttrsWarning","RecordTransaction","nested_1","_log","nested_2","changes_1","_b","emptyOptions","a_options","getHooks","transforms","changeHandlers","type","toJSON","changeEvents","hasCustomDefault","defaultValue","tools.isValidJSON","isRequired","convert","getHook_1","getHook","reduce","chainGetHooks","validate_1","chainTransforms","handleChange","chainChangeHandlers","doInit","AnyType","model","v","isChanged","code","text","New value","Prev. value","prevHook","nextHook","prevTransform","nextTransform","prevHandler","nextHandler","ImmutableClassType","PrimitiveType","NumericType","num","isFinite","ArrayType","ObjectType","doNothing","FunctionType","DateType","date","timestamp","getTime","toISOString","supportsDate","isNaN","struct","minutesOffset","isoDatePattern","exec","k","numericKeys","undefined","UTC","safeParseDate","AggregatedType","clone","canBeUpdated","nestedTransaction","_shared","persistent","_handleChange","unset","dispose","shareAndListen","listen","share","SharedType","implicitObject","_onChange","builtins","String","Number","Boolean","metatypes","getMetatype","_metatype","idx","ChainableAttributeSpec","check","metadata","required","ref","emptyFunction","changed","eventMap","unsubscribe","subscribe","cloned","Type","attrDef","shared","inferType","createAttribute","from","createAttributesMixin","attributesDefinition","baseClassAttributes","myAttributes","_.transform","allAttributes","_.defaults","ConstructorsMixin","attrDefs","attrs","attr","Attributes","constructorsMixin","_attributesArray","createPropertyDescriptor","attrSpecs","eventsApi.EventMap","createWatcherFromRef","wrapWatcher","localEventsMixin","watcher","IORecordMixin","save","getEndpoint","ioMethod","isNew","id","fetch","read","destroy","remove","_cidCounter","typeCheck","Record","idAttribute","extend","diff","hasChanged","val","old","nullify","forEach","_attributesArray_1","copy","pinStore","errors","asJson","l","newModel","clear","a_logger","Attributes definition","a_fun","tools.transform","Symbol","iterator","RecordEntriesIterator","Collection","BaseRecordAttributes","BaseRecordAttributesCopy","IdAttribute","metatype","done","DefaultCollection","dynamicMixin","_aquire","_free","convertAndAquire","_aggregationError","_itemEvents","sortElements","_comparator","sort","models","addIndex","index","removeIndex","updateIndex","previous","added","removed","sorted","CollectionTransaction","logAggregationError","added_1","_d","removed_1","_e","addTransaction","items","a_items","forceMerge","_byId","prevLength","a_items_1","item","appendElements","needSort","at","length_1","j","moveElements","sortOrMoveElements","removeMany","toRemove","_removeFromIndex","_reallocate","silentOptions","emptySetTransaction","len","src","_reallocateEmpty","setTransaction","_prevById","prevModels","toAdd","orderKept","reusedCount","previous_1","_garbageCollect","children","children_1","freeAll","addedOrChanged","ArrayMixin","mapFilter","res","doWhile","init","end","modelOrId","idOrObj","toPredicateFunction","m","firstMatch","find","entries","a_index","noOp","keys_1","keys_2","_count","CollectionRefsType","records","comparator","toElements","Refs","RefsCollection","_SubsetOf","Subset","itemEvents","aa","bb","_store","objOrId","count","elements","add","reset","enabled","liveUpdates","filter_1","_liveUpdates","updated","tslib_1.__assign","aggregated","a_elements","previousModels","previousModels_1","toDispose","recordsOrIds","el","splice","notify","removeOne","a_next","Argument","Attributes spec","parsed","parseReference","collectionRef","RecordRefType","subsetOf","masterCollection","T","CollectionClass","SubsetOf","subsetOfBehavior","refs","toArray","SubsetOfCollection","resolvedWith","resolveRefs","delaySet","raw","toggle","addAll","getMasterCollection","createSubset","subset","master","elements_1","tools.notEqual","Store","store","global","listenToOnce","method","reject","onAbort","fn","Promise","a_resolve","a_reject","listName","DefaultRecord","attrName","getMetadata","value_1","as"],"mappings":"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"} \ No newline at end of file diff --git a/docs/build.js b/docs/build.js index 6deb930f..bb5a258c 100644 --- a/docs/build.js +++ b/docs/build.js @@ -10,6 +10,7 @@ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under */ +console.info( 'Building Type-R docs...' ); var marked = require('marked') var fs = require('fs') @@ -48,7 +49,7 @@ Handlebars.registerHelper('html', function (content) { return new Handlebars.SafeString(content) }) -fs.readFile('./docs/index.md', 'utf8', function (err, content) { +fs.readFile('./index.md', 'utf8', function (err, content) { if (err) console.log(err) content = content.split(/---/g) @@ -92,13 +93,13 @@ fs.readFile('./docs/index.md', 'utf8', function (err, content) { // create partials for (var i = 0; i < data.includes.length; i++) { var includeFileName = data.includes[i] - var includeFilePath = path.resolve(__dirname, './chapters', includeFileName + '.md') + var includeFilePath = path.resolve(__dirname, '..', includeFileName + '.md') var includeContent = fs.readFileSync(includeFilePath, {encoding: 'utf8'}) var markedInclude = marked(includeContent) Handlebars.registerPartial(includeFileName, markedInclude) } } - fs.readFile('./docs/lib/layouts/layout.html', 'utf8', function (err, source) { + fs.readFile('./lib/layouts/layout.html', 'utf8', function (err, source) { if (err) console.log(err) if (data.includes) { @@ -113,8 +114,10 @@ fs.readFile('./docs/index.md', 'utf8', function (err, content) { var template = Handlebars.compile(source) data['content'] = marked(content.slice(2).join('')) - fs.writeFile('./docs/index.html', template(data), function (err) { - if (err) console.log(err) + fs.writeFile('../index.html', template(data), function (err) { + if (err){ + console.log(err); + } }) }) }) diff --git a/docs/chapters/collection.md b/docs/chapters/collection.md deleted file mode 100644 index 9e10619e..00000000 --- a/docs/chapters/collection.md +++ /dev/null @@ -1,433 +0,0 @@ -# Collection - -Collections are ordered sets of records. The collection is an array-like object exposing ES6 Array and BackboneJS Collection interface. It encapsulates JS Array of records (`collection.models`) and a hashmap for a fast O(1) access by the record `id` and `cid` (`collection.get( id )`). - -Collactions are deeply observable. You can bind "changes" events to be notified when the collection has been modified, listen for the record "add", "remove", and "change" events. - -Every `Record` class has an implicitly defined `Collection` accessible as a static member of a record's constructor. In a most cases, you don't need to define the custom collection class. - -```javascript -@define class Book extends Record { - static attributes = { - title : String - author : Author - } -} - -// Implicitly defined collection. -const books = new Book.Collection(); -``` -```typescript -@define class Book extends Record { - @auto title : string - @auto author : Author - - // Tell TypeScript the proper type. - static Collection : CollectionConstructor -} - -const books = new Book.Collection(); -``` - -You can define custom collection classes extending `Record.Collection` or any other collection class. It can either replace the default Collection type, or - -```javascript -// Define custom collection class. -@define class Library extends Record.Collection { - doSomething(){ ... } -} - -@define class Book extends Record { - // Override the default collection. - static Collection = Library; -} - -// Define another custom collection class. -@define class OtherLibrary extends Record.Collection { - // Specify the record so the collection will be able to restore itself from JSON. - static model = Book; -} -``` -```typescript -// Define custom collection class. -@define class Library extends Collection { - doSomething(){ ... } -} - -@define class Book extends Record { - // Override the default collection. - static Collection = Library; -} - -// Define another custom collection class. -@define class OtherLibrary extends Collection { - // Specify the record so the collection will be able to restore itself from JSON. - static model = Book; -} - -// An alternative way of overriding the default collection class in TypeScript. -namespace Book { - @define class Collection extends Collection { - static model = Book; - } -} -``` - - - -## Collection types - -### `constructor` CollectionClass( records?, options? ) - -The most common collection type is an **aggregating serializable collection**. By default, collection aggregates its elements which are treated as an integral part of the collection (serialized, cloned, disposed, and validated recursively). An aggregation means the _single owner_, as the single object cannot be an integral part of two distinct things. The collection will take ownership on its records and will put an error in the console if it can't. - -When creating a Collection, you may choose to pass in the initial array of records. - -```javascript -@define class Role extends Record { - static attributes = { - name : String - } -} - -const roles = new Role.Collection( json, { parse : true } ); -``` - -```typescript -@define class Role extends Record { - // In typescript, you have to specify record's Collection type expicitly. - static Collection : CollectionConstructor - - @auto name : string -} - -@define class User extends Record { - @auto name : string - - // Type-R cannot infer a Collection metatype from the TypeScript type automatically. - // Full attribute type annotation is required. - @type( Role.Collection ).as roles : Collection -} -``` - -### `constructor` CollectionClass.Refs( records?, options? ) - -Collection of record references is a **non-aggregating non-serializable collection**. `Collection.Refs` doesn't aggregate its elements, which means that containing records are not considered as an integral part of the enclosing collection and not being validated, cloned, disposed, and serialized recursively. - -It is useful for a local non-persistent application state. - -### `attrDef` subsetOf(masterRef, CollectionClass?) - -The subset of other collections are **non-aggregating serializable collection**. Subset-of collection is serialized as an array of record ids and used to model many-to-many relationships. The collection object itself is recursively created and cloned, however, its records are not aggregated by the collection thus they are not recursively cloned, validated, or disposed. `CollectionClass` argument may be omitted unless you need the record's attribute to be an instance of the particular collection class. - - - - - -Must have a reference to the master collection which is used to resolve record ids to records. `masterRef` may be: - -- direct reference to a singleton collection. -- function, returning the reference to the collection. -- symbolic dot-separated path to the master collection resolved relative to the record's `this`. You may use `owner` and `store` macro in path: - - `owner` is the reference to the record's owner. `owner.some.path` works as `() => this.getOwner().some.path`. - - `store` is the reference to the closes store. `store.some.path` works as `() => this.getStore().some.path`. - -```javascript -@define class Role extends Record { - static attributes = { - name : String, - ... - } -} - -@define class User extends Record { - static attributes = { - name : String, - roles : subsetOf( 'owner.roles', Role.Collection ) - } -} - -@define class UsersDirectory extends Store { - static attributes = { - roles : Role.Collection, - users : User.Collection // `~roles` references will be resolved against this.roles - } -} -``` -```typescript -@define class Role extends Record { - static Collection : CollectionConstructor - - @auto name : string - ... -} - -@define class User extends Record { - static Collection : CollectionConstructor - - @auto name : string - @subsetOf('store.roles').as roles : Collection -} - -@define class UsersDirectory extends Store { - @type(Role.Collection).as roles : Collection, - @type(User.Collection).as users : Collection // <- `store.roles` references will be resolved against this.roles -} -``` - -## Array API - -A collection class is an array-like object implementing ES6 Array methods and properties. - -### collection.length - -Like an array, a Collection maintains a length property, counting the number of records it contains. - -### collection.slice( begin, end ) - -Return a shallow copy of the `collection.models`, using the same options as native Array#slice. - -### collection.indexOf( recordOrId : any ) : number - -Return an index of the record in the collection, and -1 if there is no such a record in the collection. - -Can take the record itself as an argument, `id`, or `cid` of the record. - -### collection.forEach( iteratee : ( val : Record, index ) => void, context? ) - -Iterate through the elements of the collection. - - - -### collection.map( iteratee : ( val : Record, index ) => T, context? ) - -Map elements of the collection. Similar to `Array.map`. - -### collection.filter( iteratee : Predicate, context? ) - -Return the filtered array of records matching the predicate. - -The predicate is either the iteratee function returning boolean, or an object with attribute values used to match with record's attributes. - -### collection.every( iteratee : Predicate, context? ) : boolean - -Return `true` if all records match the predicate. - -### collection.some( iteratee : Predicate, context? ) : boolean - -Return `true` if at least one record matches the predicated. - -### collection.push( record, options? ) - -Add a record at the end of a collection. Takes the same options as `add()`. - -### collection.pop( options? ) -Remove and return the last record from a collection. Takes the same options as `remove()`. - -### collection.unshift( record, options? ) - -Add a record at the beginning of a collection. Takes the same options as `add()`. - -### collection.shift( options? ) -Remove and return the first record from a collection. Takes the same options as `remove()`. - -## Backbone API - -Common options used by Backbone API methods: - -- `{ sort : false }` - do not sort the collection. -- `{ parse : true }` - parse raw JSON (used to set collection with data from the server). - -### `callback` collection.initialize( records?, options? ) - -Initialization function which is called at the end of the constructor. - -### collection.clone() - -Clone the collection. An aggregating collection will be recursively cloned, non-aggregated collections will be shallow cloned. - -### collection.models - -Raw access to the JavaScript array of records inside of the collection. Usually, you'll want to use `get`, `at`, or the other methods to access record objects, but occasionally a direct reference to the array is desired. - -### collection.get( id ) -Get a record from a collection, specified by an `id`, a `cid`, or by passing in a record. - -```javascript -const book = library.get(110); -``` - -### collection.at( index ) - -Get a record from a collection, specified by index. Useful if your collection is sorted, and if your collection isn't sorted, at will still retrieve records in insertion order. When passed a negative index, it will retrieve the record from the back of the collection. - -### collection.add( records, options? ) - -Add a record (or an array of records) to the collection. If this is the `Record.Collection`, you may also pass raw attributes objects, and have them be vivified as instances of the `Record`. Returns the added (or preexisting, if duplicate) records. - -Pass `{at: index}` to splice the record into the collection at the specified index. If you're adding records to the collection that are already in the collection, they'll be ignored, unless you pass `{merge: true}`, in which case their attributes will be merged into the corresponding records. - -1. Trigger the one event per record: - - `add`(record, collection, options) for each record added. - - `change`(record, options) for each record changed (if the `{merge: true}` option is passed). -3. Trigger the single event: - - `update`(collection, options) if any records were added. - - `sort`(collection, options) if an order of records was changed. -4. Trigger `changes` event in case if any changes were made to the collection and objects inside. - -### collection.remove( records, options? ) - -Remove a record (or an array of records) from the collection, and return them. Each record can be a record instance, an id string or a JS object, any value acceptable as the id argument of collection.get. - -1. Trigger `remove`(record, collection, options) for each record removed. -3. If any records were removed, trigger: - - `update`(collection, options) - - `changes`(collection, options). - -### collection.set( records, options? ) - -The set method performs a "smart" update of the collection with the passed list of records. If a record in the list isn't yet in the collection it will be added; if the record is already in the collection its attributes will be merged; and if the collection contains any records that aren't present in the list, they'll be removed. All of the appropriate "add", "remove", and "change" events are fired as this happens. Returns the touched records in the collection. If you'd like to customize the behavior, you can disable it with options: `{remove: false}`, or `{merge: false}`. - -#### Events -1. Trigger the one event per record: - - `add`(record, collection, options) for each record added. - - `remove`(record, collection, options) for each record removed. - - `change`(record, options) for each record changed. -3. Trigger the single event: - - `update`(collection, options) if any records were added. - - `sort`(collection, options) if an order of records was changed. -4. Trigger `changes` event in case if any changes were made to the collection and objects inside. - -```javascript -const vanHalen = new Man.Collection([ eddie, alex, stone, roth ]); - -vanHalen.set([ eddie, alex, stone, hagar ]); - -// Fires a "remove" event for roth, and an "add" event for hagar. -// Updates any of stone, alex, and eddie's attributes that may have -// changed over the years. -``` - -### collection.reset(records, options?) - -Replace the collection's content with the new records. More efficient than `collection.set`, but does not send record-level events. - -Calling `collection.reset()` without passing any records as arguments will empty the entire collection. - -1. Trigger event `reset`(collection, options). -2. Trigger event `changes`(collection, options). - -### collection.pluck(attribute) - -Pluck an attribute from each model in the collection. Equivalent to calling map and returning a single attribute from the iterator. - -```javascript -const users = new UserCollection([ - {name: "Curly"}, - {name: "Larry"}, - {name: "Moe"} -]); - -const names = users.pluck("name"); - -alert(JSON.stringify(names)); -``` - -## Sorting - -Type-R implements BackboneJS Collection sorting API with some extensions. - -### collection.sort(options?) - -Force a collection to re-sort itself. You don't need to call this under normal circumstances, as a collection with a comparator will sort itself whenever a record is added. To disable sorting when adding a record, pass `{sort: false}` to add. Calling sort triggers a "sort" event on the collection. - -By default, there is no comparator for a collection. If you define a comparator, it will be used to maintain the collection in sorted order. This means that as records are added, they are inserted at the correct index in `collection.models`. - -Note that Type-R depends on the arity of your comparator function to determine between the two styles, so be careful if your comparator function is bound. - -Collections with a comparator will not automatically re-sort if you later change record attributes, so you may wish to call sort after changing record attributes that would affect the order. - -### `static` comparator = 'attrName' - -Maintain the collection in sorted order by the given record's attribute. - -### `static` comparator = x => number | string - -Maintain the collection in sorted order according to the "sortBy" comparator function. - -"sortBy" comparator functions take a record and return a numeric or string value by which the record should be ordered relative to others. - -### `static` comparator = (x, y) => -1 | 0 | 1 - -Maintain the collection in sorted order according to the "sort" comparator function. - -"sort" comparator functions take two records and return -1 if the first record should come before the second, 0 if they are of the same rank and 1 if the first record should come after. - -Note how even though all of the chapters in this example are added backward, they come out in the proper order: - -```javascript -@define class Chapter extends Record { - static attributes = { - page : Number, - title : String - } -} - -var chapters = new Chapter.Collection(); - -chapters.comparator = 'page'; - -chapters.add({page: 9, title: "The End"}); -chapters.add({page: 5, title: "The Middle"}); -chapters.add({page: 1, title: "The Beginning"}); - -alert(chapters.map( x => x.title )); -``` - -## Other methods - -### CollectionClass.from( models, options? ) - -Create `CollectionClass` from the array of models. Similar to direct collection creation, but supports additional option for strict data validation. -If `{ strict : true }` option is passed the validation will be performed and an exception will be thrown in case of an error. - -Please note, that Type-R always performs type checks on assignments, convert types, and reject improper updates reporting it as an error. It won't, however, execute custom validation -rules on every update as they are evaluated lazily. `strict` option will invoke custom validators and will throw on every error or warning instead of reporting them and continue. - -```javascript -// Validate the body of an incoming HTTP request. -// Throw an exception if validation fails. -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true }); -``` - -```typescript -// Validate the body of an incoming HTTP request. -// Throw an exception if validation fails. -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true }); -``` - -### collection.createSubset( records?, options? ) - -Create the collection which is a subset of a source collection serializable as an array of record ids. Takes the same arguments as the collection's constructor. - -The created collection is an instance of `subsetOf( sourceCollection, CollectionCtor )` attribute type (non-aggregating serializable collection). - - - -### collection.assignFrom( otherCollection ) - -Synchronize the state of the collection and its aggregation tree with other collection of the same type. Updates existing objects in place. Record in the collection is considered to be "existing" if it has the same `id`. - -Equivalent to `collection.set( otherCollection.models, { merge : true } )` and triggers similar events on change. - -### collection.dispose() - -Dispose of the collection. An aggregating collection will recursively dispose of its records. \ No newline at end of file diff --git a/docs/chapters/core.md b/docs/chapters/core.md deleted file mode 100644 index 028a6a99..00000000 --- a/docs/chapters/core.md +++ /dev/null @@ -1,403 +0,0 @@ -# Core Data Structires -## Overview - -## Aggregation Tree - -## Definitions - -Record definition must: - -- be the class extending the `Record`; -- be preceded with the `@define` decorator; -- have `static attributes` definition. - -### `decorator` @define - -_Must_ be placed before record class definition. - -```javascript -import { define, Record } from 'type-r' - -@define class X extends Record { - ... -} -``` - -### `static` attributes = { name : `attrDef`, ... } - -Record's attributes definition. Lists attribute names along with their types, default values, and metadata controlling different aspects of attribute behavior. - -```javascript -@define class User extends Record { - static attributes = { - name : type( String ).value( 'John Dow' ), - email : 'john.dow@mail.com', // Same as type( String ).value( 'john.dow@mail.com' ) - address : String, // Same as type( String ).value( '' ) - } -} -``` - -The Record guarantee that _every attribute will retain the value of the declared type_. Whenever an attribute is being assigned with the value which is not compatible with its declared type, the type is being converted with an invocation of the constructor: `new Type( value )` (primitive types are treated specially). - -### `static` idAttribute = 'attrName' - -A record's unique identifier is stored under the pre-defined `id` attribute. -If you're directly communicating with a backend (CouchDB, MongoDB) that uses a different unique key, you may set a Record's `idAttribute` to transparently map from that key to id. - -Record's `id` property will still be linked to Record's id, no matter which value `idAttribute` has. - -```javascript -@define class Meal extends Record { - static idAttribute = "_id"; - static attributes = { - _id : Number, - name : '' - } -} - -const cake = new Meal({ _id: 1, name: "Cake" }); -alert("Cake id: " + cake.id); -``` - -### `attrDef` : Type - -When the function is used as `attrDef`, it's treated as the constructor function. Any constructor function which behaves as _converting constructor_ (like `new Date( msecs )`) may be used as an attribute type. - -```javascript -@define class Person extends Record { - static attributes = { - name : String // String attribute which is "" by default. - createdAt : Date // Date attribute - ... - } -} -``` - -### `attrDef` : defaultValue - -When value of other type than function is used as `attrDef` it's treated as attribute's default value. Attribute's type is being inferred from the value. - -Use the general form of attribute definition for attributes of `Function` type: `type( Function ).value( theFunction )`. - -```javascript -@define class GridColumn extends Record { - static attributes = { - name : '', // String attribute which is '' by default. - render : type( Function ).value( x => x ), - ... - } -} -``` - -### `attrDef` : type( Type ).value( defaultValue ) - -Declare attribute with custom default value. - -```javascript -@define class Person extends Record { - static attributes = { - phone : type( String ).value( null ) // String attribute which is null by default. - ... - } -} -``` - -The record is _recursive_ if it's uses the type of itself in its attribute definition. - -### `attrDef` : Date - -Date attribute initialized as `new Date()`. Represented in JSON as string or number depending on the type: - -* `Date` - as ISO date string. -* `Date.microsoft` - as Microsoft's `"/Date(msecs)/"` string. -* `Date.timestamp` - as UNIX integer timestamp. - -### `static` Collection - -The default record's collection class automatically defined for every Record subclass. Can be referenced as `Record.Collection`. - -May be explicitly assigned in record's definition with custom collection class. - -```javascript -// Declare the collection class. -@define class Comments extends Record.Collection {} - -@define class Comment extends Record({ - static Collection = Comments; // Make it the default Comment collection. - - attributes : { - text : String, - replies : Comments - } -}); -``` - -## Record - -Record behaves as regular ES6 class with attributes accessible as properties. - -### new Record() - -Create an instance of the record with default attribute values taken from the attributes definition. - -When no default value is explicitly provided for an attribute, it's initialized as `new Type()` (just `Type()` for primitives). When the default value is provided and it's not compatible with the attribute type, it's converted with `new Type( defaultValue )` call. - -### new Record({ attrName : value, ... }, options? ) - -When creating an instance of a record, you can pass in the initial attribute values to override the defaults. - -If `{parse: true}` option is used, `attrs` is assumed to be the JSON. - -If the value of the particular attribute is not compatible with its type, it's converted to the declared type invoking the constructor `new Type( value )` (just `Type( value )` for primitives). - -```javascript -@define class Book extends Record { - static attributes = { - title : '', - author : '' - } -} - -const book = new Book({ - title: "One Thousand and One Nights", - author: "Scheherazade" -}); -``` - -### record.clone() - -Create the deep copy of the aggregation tree, recursively cloning all aggregated records and collections. References to shared members will be copied, but not shared members themselves. - -### `callback` record.initialize( attrs?, options? ) - -Called at the end of the `Record` constructor when all attributes are assigned and the record's inner state is properly initialized. Takes the same arguments as -a constructor. - -### record.dispose() - -Recursively dispose the record and its aggregated members. "Dispose" means that elements of the aggregation tree will unsubscribe from all event sources. It's crucial to prevent memory leaks in SPA. - -The whole aggregation tree will be recursively disposed, shared members won't. - -### record.cid - -Read-only client-side record's identifier. Generated upon creation of the record and is unique for every record's instance. Cloned records will have different `cid`. - -### record.id - -Predefined record's attribute, the `id` is an arbitrary string (integer id or UUID). `id` is typically generated by the server. It is used in JSON for id-references. - -Records can be retrieved by `id` from collections, and there can be just one instance of the record with the same `id` in the particular collection. - -### record.isNew() - -Has this record been saved to the server yet? If the record does not yet have an `id`, it is considered to be new. - -### record.attrName - -Record's attributes may be directly accessed as `record.name`. - - - -```javascript -@define class Account extends Record { - static attributes = { - name : String, - balance : Number - } -} - -const myAccount = new Account({ name : 'mine' }); -myAccount.balance += 1000000; // That works. Good, eh? -``` - -### record.attrName = value - -Assign the record's attribute. If the value is not compatible with attribute's type from the declaration, it is converted: - -- with `Type( value )` call, for primitive types; -- with `record.attrName.set( value )`, for existing record or collection (updated in place); -- with `new Type( value )` in all other cases. - -Record triggers events on changes: -- `change:attrName` *( record, value )*. -- `change` *( record )*. - -```javascript -@define class Book extends Record { - static attributes = { - title : String, - author : String - price : Number, - publishedAt : Date, - available : Boolean - } -} - -const myBook = new Book({ title : "State management with Type-R" }); -myBook.author = 'Vlad'; // That works. -myBook.price = 'Too much'; // Converted with Number( 'Too much' ), resulting in NaN. -myBook.price = '123'; // = Number( '123' ). -myBook.publishedAt = new Date(); // Type is compatible, no conversion. -myBook.publishedAt = '1678-10-15 12:00'; // new Date( '1678-10-15 12:00' ) -myBook.available = some && weird || condition; // Will always be Boolean. Or null. -``` - -### record.set( { attrName : value, ... }, options? : `options` ) - -Bulk assign record's attributes, possibly taking options. - -If the value is not compatible with attribute's type from the declaration, it is converted: - -- with `Type( value )` call, for primitive types. -- with `record.attrName.set( value )`, for existing record or collection (updated in place). -- with `new Type( value )` in all other cases. - -Record triggers events after all changes are applied: - -1. `change:attrName` *( record, val, options )* for any changed attribute. -2. `change` *(record, options)*, if there were changed attributes. - -### record.assignFrom( otherRecord ) - -Makes an existing `record` to be the full clone of `otherRecord`, recursively assigning all attributes. - -```javascript -// Another way of doing the bestSeller.clone() -const book = new Book(); -book.assignFrom( bestSeller ); -``` - -### record.transaction( fun ) - -Execute the all changes made to the record in `fun` as single transaction triggering the single `change` event. - -All record updates occurs in the scope of transactions. Transaction is the sequence of changes which results in a single `change` event. -Transaction can be opened either manually or implicitly with calling `set()` or assigning an attribute. -Any additional changes made to the record in `change:attr` event handler will be executed in the scope of the original transaction, and won't trigger additional `change` events. - - -```javascript -some.record.transaction( record => { - record.a = 1; // `change:a` event is triggered. - record.b = 2; // `change:b` event is triggered. -}); // `change` event is triggered. -``` - -Manual transactions with attribute assignments are superior to `record.set()` in terms of both performance and flexibility. - -### `attrDef` : type( Type ).get( `hook` ) - -Attach get hook to the record's attribute. `hook` is the function of signature `( value, attr ) => value` which is used to transform the attribute's value _before it will be read_. Hook is executed in the context of the record. - -### `attrDef` : type( Type ).set( `hook` ) - -Attach the set hook to the record's attribute. `hook` is the function of signature `( value, attr ) => value` which is used to transform the attribute's value _before it will be assigned_. Hook is executed in the context of the record. - -If set hook will return `undefined`, it will cancel attribute update. - -## Collection - -## Nested records and collections - -Record's attributes can hold other Records and Collections, forming indefinitely nested data structures of arbitrary complexity. -To create nested record or collection you should just mention its constructor function in attribute's definition. - -```javascript -import { Record } from 'type-r' - -@define class User extends Record { - static attributes = { - name : String, - email : String, - isActive : true - } -} - -@define class UsersListState extends Record { - static attributes = { - users : User.Collection - } -} -``` - -All nested records and collections are *aggregated* by default and behave as integral parts of the containing record. Aggregated attributes are _exclusively owned_ by the record, and taken with it together form an _ownership tree_. Many operations are performed recursively on aggregated elements: - -- They are created when the owner record is created. -- They are cloned when the record is cloned. -- They are disposed when the record is disposed. -- They are validated as part of the record. -- They are serialized as nested JSON. - -### `attrDef` : RecordOrCollection - -Aggregated record or collection. Represented as nested object or array in record's JSON. Aggregated members are owned by the record and treated as its _integral part_ (recursively created, cloned, serialized, validated, and disposed). -One object can have single owner. The record with its aggregated attributes forms an _aggregation tree_. - -All changes in aggregated record or collections are detected and cause change events on the containing record. - -### record.getOwner() - -Return the record which is an owner of the current record, or `null` there are no one. - -Due to the nature of _aggregation_, an object may have one and only one owner. - -### record.collection - -Return the collection which aggregates the record, or `null` if there are no one. - -### `attrDef` : shared( RecordOrCollection ) - -Non-serializable reference to the record or collection possibly from the different aggregation tree. Initialized with `null`. Is not recursively cloned, serialized, validated, or disposed. - -All changes in shared records or collections are detected and cause change events of the containing record. - - - -```javascript -@define class UsersListState extends Record { - static attributes = { - users : User.Collection, - selected : shared( User ) // Can be assigned with the user from this.users - } -} -``` - -### `attrDef` : Collection.Refs - -Non-aggregating collection. Collection of references to shared records which itself is _aggregated_ by the record, but _does not aggregate_ its elements. In contrast to the `shared( Collection )`, `Collection.Refs` creates an instance of collection which _is the part the parent record_. - -The collection itself is recursively created and cloned. However, its records are not aggregated by the collection thus they are not recursively cloned, validated, serialized, or disposed. - -All changes in the collection and its elements are detected and cause change events of the containing record. - - - -```javascript - @define class MyRecord extends Record { - static attributes = { - notCloned : shared( SomeCollection ), // Reference to the _shared collection_ object. - cloned : SomeCollection.Refs // _Aggregated_ collection of references to the _shared records_. - } -``` - -### `decorator` @predefine - -Make forward declaration for the record to define its attributes later with `RecordClass.define()`. Used instead of `@define` for recursive record definitions. - -Creates the default `RecordClass.Collection` type which can be referenced in attribute definitions. - -### `static` define({ attributes : { name : `attrDef`, ... } }) - -May be called to define attributes in conjunction with `@predefine` decorator to make recursive record definitions. - -```javascript -@predefine class Comment extends Record{} - -Comment.define({ - attributes : { - text : String, - replies : Comment.Collection - } -}); -``` diff --git a/docs/chapters/io.md b/docs/chapters/io.md deleted file mode 100644 index 6a601ef6..00000000 --- a/docs/chapters/io.md +++ /dev/null @@ -1,507 +0,0 @@ -# I/O and Serialization - -## Overview - -Type-R implements generalized IO on top of the `IOEndpoint` interface, with JSON serialization handled by Record and Collection classes. - -IOEndpoint defines the set of CRUD + list methods operating on raw JSON. -Attachment of an endpoint to the record or collection enables I/O API. There are few endpoints bundled with Type-R, for instance `memoryIO()` which can be used for mock testing. - -```javascript -@define class User extends Record { - static endpoint = memoryIO(); - - static attributes = { - name : '', - email : '' - } -} - -const users = new User.Collection(); -users - .add({ name : 'John' }) - .save() - .then( () => console.log( user.id ); -``` - -## I/O API - -### `static` endpoint - -I/O endpoint declaration which should be used in Record or Collection definition to enable I/O API. - -If an endpoint is defined for the `MyRecord`, it's automatically defined for the corresponding `MyRecord.Collection` as well. - -### `attrDef` : type( Type ).endpoint( `endpoint` ) - -Override or define an I/O endpoint for the specific record's attribute. - -### obj.getEndpoint() - -Returns an object's IO endpoint. Normally, this is an endpoint which is defined in object's `static endpoint = ...` declaration, but it might be overridden by the parent's record using `type( Type ).endpoint( ... )` attribute declaration. - -```javascript -@define class User extends Record { - static endpoint = restfulIO( '/api/users' ); - ... -} - -@define class UserRole extends Record { - static endpoint = restfulIO( '/api/roles' ); - static attributes = { - // Use the relative path '/api/roles/:id/users' - users : type( User.Collection ).endpoint( restfulIO( './users' ) ), - ... - } -} -``` - -### record.fetch( options? ) - -Asynchronously fetch the record using `endpoint.read()` method. Returns an abortable ES6 promise. - -An endpoint must be defined for the record in order to use that method. - -### record.save( options? ) - -Asynchronously save the record using `endpoint.create()` (if there are no id) or `endpoint.update()` (if id is present) method. Returns an abortable ES6 promise. - -An endpoint must be defined for the record in order to use that method. - -### record.destroy( options? ) - -Asynchronously destroy the record using `endpoint.destroy()` method. Returns an abortable ES6 promise. The record is removed from the aggregating collection upon the completion of the I/O request. - -An endpoint must be defined for the record in order to use that method. - -### collection.fetch( options? ) - -Fetch the collection. Returns an abortable promise. - -`options` accepts an optional `liveUpdates` parameter. When `true`, collection subscribes for the live updates when I/O is finished. - -### collection.liveUpdates( true | false ) - -Subscribe for the live data updates if an I/O endpoint supports it (`subscribe()`/`unsubscribe()` IOEndpoint methods). - - - -### obj.hasPendingIO() - -Returns an abortable promise if there's any I/O pending with the object, or `null` otherwise. - -Can be used to check for active I/O in progress or to abort pending I/O operation. Please note, that all pending I/O is aborted automatically when new I/O operation is started or an object is disposed. When I/O is aborted, the promise is rejected. - -```javascript -const promise = users.hasPendingIO(); -if( promise && promise.abort ) promise.abort(); -``` - -## I/O endpoints - -### restfulIO( url, options? ) - -HTTP REST client endpoint. Requires `window.fetch` available natively or through the polyfill. Implements standard BackboneJS REST semantic. - -All I/O methods append an optional `options.params` object to the URL parameters translating them to string with `JSON.stringify()`. - -- `record.save()` makes: - - `POST url`, if the model has no id. Expects to receive `{ id : recordId }`. - - `PUT url/:id`, if the model has an id. -- `collection.fetch()` makes `GET url`. -- `record.destroy()` makes `DELETE url`. - -Supports URI relative to owner (`./relative/url` resolves as `/owner/:id/relative/url/:id` ). - -```javascript -import { restfulIO } from 'type-r/endpoints/restful' - -@define class Role extends Record { - static endpoint = restfulIO( '/api/roles' ); - ... -} - -@define class User extends Record { - static endpoint = restfulIO( '/api/users' ); - - static attributes = { - // Roles collection here has relative url /api/users/:user_id/roles/ - roles : type( Role.Collection ).endpoint( restfulIO( './roles' ) ), - ... - } -} -``` - -### memoryIO( mockData?, delay? ) - -Endpoint for mock testing. Takes optional array with mock data, and optional `delay` parameter which is the simulated I/O delay in milliseconds. - -```javascript -import { memoryIO } from 'type-r/endpoints/memory' - -@define class User extends Record { - static endpoint = memoryIO(); - ... -} -``` - -### localStorageIO( key ) - -Endpoint for localStorage. Takes `key` parameter which must be unique for the persistent record's collection. - -```javascript -import { localStorageIO } from 'type-r/endpoints/localStorage' - -@define class User extends Record { - static endpoint = localStorageIO( '/users' ); - ... -} -``` - -### attributesIO() - -Endpoint for I/O composition. Redirects record's `fetch()` request to its attributes and returns the combined abortable promise. Does not enable any other I/O methods and can be used with `record.fetch()` only. - -It's common pattern to use attributesIO endpoint in conjunction with Store to fetch all the data required by SPA page. - -```javascript -import { localStorageIO } from 'type-r/endpoints/attributes' - -@define class PageStore extends Store { - static endpoint = attributesIO(); - static attributes = { - users : User.Collection, - roles : UserRole.Collection, - } -} -... -const store = new PageStore(); -store.fetch().then( () => renderUI() ); -``` - -### proxyIO( RecordCtor ) - -Create IO endpoint from the Record class. This endpoint is designed for use on the server side with a data layer managed by Type-R. - -Assuming that you have Type-R records with endpoints working with the database, you can create an endpoint which will use -an existing Record subclass as a transport. This endpoint can be connected to the RESTful endpoint API on the server side which will serve JSON to the restfulIO endpoint on the client. - -An advantage of this approach is that JSON schema will be transparently validated on the server side by the Type-R. - -```javascript - import { proxyIO } from 'type-r/endpoint/proxy' - - ... - - const usersIO = proxyIO( User ); -``` - -## IOEndpoint Interface - -An IO endpoint is an "plug-in" abstraction representing the persistent collection of JSON objects, which is required to enable records and collections I/O API. There are several pre-defined endpoints included in Type-R package which can be used for HTTP REST I/O, mock testing, working with localStorage, and IO composition. - -You will need to define custom endpoint if you would like to implement or customize serialization transport for Type-R objects. Use built-in endpoints as an example and the starting boilerplate. - -All IOEndpoint methods might return standard Promises or abortable promises (created with `createIOPromise()`). An IOEndpoint instance is shared by all of the class instances it's attached to and therefore it's normally *must be stateless*. - -### endpoint.read( id, options, record ) - -Reads an object with a given id. Used by `record.fetch()` method. Must return JSON wrapped in abortable promise. - -### endpoint.update( id, json, options, record ) - -Updates or creates an object with a given id. Used by `record.save()` method when record *already has* an id. Must return abortable promise. - -### endpoint.create( json, options, record ) - -Creates an object. Used by `record.save()` method when record *does not* have an id. Must return abortable promise. - -### endpoint.destroy( id, options, record ) - -Destroys the object with the given id. Used by `record.destroy()` method. Must return abortable promise. - -### endpoint.list( options, collection ) - -Fetch an array of objects. Used by `collection.fetch()` method. Must returns abortable promise. - -### endpoint.subscribe( `callbacks`, collection ) - -Optional method to enable the live updates subscription. Used by `collection.liveUpdates( true )` method. Must returns abortable promise. - -Method `callbacks` argument is an object of the following shape: - -```javascript -{ - // Endpoint must call it when an object is created or updated. - updated( json ){} - - // Endpoint must call it when an object is removed. - removed( json ){} -} -``` - -### endpoint.unsubscribe( `callbacks`, collection ) - -Unsubscribe from the live updates. Used by `collection.liveUpdates( false )` method. Takes the same `callbacks` object as `subscribe()`. - -### createIOPromise( init ) - -Service function to create an abortable version of ES6 promise (with `promise.abort()` which meant to stop pending I/O and reject the promise). - -`init` function takes the third `onAbort` argument to register an optional abort handler. If no handler is registered, the default implementation of `promise.abort()` will just reject the promise. - -```javascript -import { createIOPromise } from 'type-r' - -const abortablePromise = createIOPromise( ( resolve, reject, onAbort ) =>{ - ... - onAbort( () => { - reject( 'I/O Aborted' ); - }); -}); -``` - -## Serialization - -Record and Collection has a portion of common API related to the I/O and serialization. - -### obj.toJSON( options? ) - -Serialize record or collection to JSON. Used internally by `save()` I/O method (`options.ioMethod === 'save'` when called from within `save()`). Can be overridden to customize serialization. - -Produces the JSON for the given record or collection and its aggregated members. Aggregation tree is serialized as nested JSON. Record corresponds to an object in JSON, while the collection is represented as an array of objects. - -If you override `toJSON()`, it usually means that you must override `parse()` as well, and vice versa. - - - -```javascript -@define class Comment extends Record { - static attributes = { - body : '' - } -} - -@define class BlogPost extends Record { - static attributes = { - title : '', - body : '', - comments : Comment.Collection - } -} - -const post = new BlogPost({ - title: "Type-R is cool!", - comments : [ { body : "Agree" }] -}); - -const rawJSON = post.toJSON() -// { title : "Type-R is cool!", body : "", comments : [{ body : "Agree" }] } -``` - -### `option` { parse : true } - -`obj.set()` and constructor's option to force parsing of the raw JSON. Is used internally by I/O methods to parse the data received from the server. - -```javascript -// Another way of doing the bestSeller.clone() -// Amazingly, this is guaranteed to work by default. -const book = new Book(); -book.set( bestSeller.toJSON(), { parse : true } ); -``` - -### `callback` obj.parse( json, options? ) - -Optional hook called to transform the JSON when it's passes to the record or collection with `set( json, { parse : true })` call. Used internally by I/O methods (`options.ioMethod` is either "save" or "fetch" when called from I/O method). - -If you override `toJSON()`, it usually means that you must override `parse()` as well, and vice versa. - - - -### `attrDef` : type( Type ).toJSON( false ) - -Do _not_ serialize the specific attribute. - -### `attrDef` : type( Type ).toJSON( ( value, name, options ) => json ) - -Override the default serialization for the specific record's attribute. - -Attribute is not serialized when the function return `undefined`. - -### `attrDef` : type( Type ).parse( ( json, name ) => value ) - -Transform the data before it will be assigned to the record's attribute. - -Invoked when the `{ parse : true }` option is set. - -```javascript -// Define custom boolean attribute type which is serialized as 0 or 1. -const MyWeirdBool = type( Boolean ) - .parse( x => x === 1 ) - .toJSON( x => x ? 1 : 0 ); -``` - -### `static` create( attrs, options ) - -Static factory function used internally by Type-R to create instances of the record. - -May be redefined in the abstract Record base class to make it serializable type. - -```javascript -@define class Widget extends Record { - static attributes = { - type : String - } - - static create( attrs, options ){ - switch( attrs.type ){ - case "typeA" : return new TypeA( attrs, options ); - case "typeB" : return new TypeB( attrs, options ); - } - } -} - -@define class TypeA extends Widget { - static attributes = { - type : "typeA", - ... - } -} - -@define class TypeB extends Widget { - static attributes = { - type : "typeB", - ... - } -} -``` - -## Normalized data - -Type-R has first-class support for working with normalized data represented as a set of collections with cross-references by record id. References are represented as record ids in JSON, and being transparently resolved to record instances on the first access. - -`Store` class is the special record class which serves as a placeholder for the set of interlinked collections of normalized records. Id-references are defined as record attributes of the special type representing the serializable reference to the records from the specified master collection. - -### `attrDef` : memberOf( `sourceCollection` ) - -Serializable reference to the record from the particular collection. -Initialized as `null` and serialized as `record.id`. Is not recursively cloned, validated, or disposed. Used to model one-to-many relationships. - -Changes in shared record are not detected. - -`sourceCollection` may be: -- the JS variable pointing to the collection singleton; -- the function returning the collection; -- the string with the dot-separated _relative object path_ to the collection. It is resolved dynamically relative to the record's `this`. Following shortcuts may be used in path: - - `owner.path` (or `^path`) works as `() => this.getOwner().path`. - - `store.path` (or `~path`) works as `() => this.getStore().path`. - -```javascript - @define class State extends Record { - static attributes = { - items : Item.Collection, - selected : memberOf( 'items' ) // Will resolve to `this.items` - } - } -``` - -```typescript - @define class State extends Record { - @type( Item.Collection ).as items : Collection; - @memberOf( 'items' ).as selected : Item - } -``` - - - -### `attrDef` : subsetOf( `sourceCollection`, CollectionCtor? ) - -Serializable non-aggregating collection which is the subset of the existing collection. Serialized as an array of record ids. Used to model many-to-many relationships. `CollectionCtor` argument may be omitted unless you need it to be a sublass of the particular collection type. - -The collection object itself is recursively created and cloned. However, its records are not aggregated by the collection thus they are not recursively cloned, validated, or disposed. - -`sourceCollection` is the same reference as used by `memberOf( sourceCollection )`. - -```javascript -@define class Role extends Record { - static attributes = { - name : String, - ... - } -} - -@define class User extends Record { - static attributes = { - name : String, - roles : subsetOf( '~roles', Role.Collection ) - } -} - -@define class UsersDirectory extends Store { - static attributes = { - roles : Role.Collection, - users : User.Collection // `~roles` references will be resolved against this.roles - } -} -``` - -### sourceCollection.createSubset( records?, options? ) - -Create an instance of `subsetOf( sourceCollection, CollectionCtor )` type (non-aggregating serializable collection) which is the subset of the given collection. Takes the same arguments as the collection's constructor. - - - -### `class` Store - -`Store` is the special kind of record which serves as a root for id references. - -For all records inside of the store's aggregation tree `~attrName` will resolve to the attribute of the store class found with `record.getStore()` method. If there are no such an attribute in the store, the next available store upper in aggregation tree will be used (as regular records stores can be nested), or the default store if there are no one. - - - -Store is the subclass of the Record. It's defined extending the `Store` abstract base class. It behaves as a regular record in most aspects. - -### store._defaultStore - -Reference to the master store used for lookups if the current store doesn't have the required attribute and there are no other store found upper in the ownership chain. - -Defaults to the `Store.global`. May be explicitly defined to create custom store lookup chains across the ownership hierarchy. - -### `static` Store.global - -The default singleton store class. Is always the last store to lookup when resolving ~reference. - -Use the default store for the _globally shared data only_. Each application page must have its local store. - -```javascript -@define class MyStore extends Store { - static attributes = { - users : User.Collection, - roles : Role.Collection - } -} - -Store.global = new MyStore(); - -// Now the reference '~users` will point to users collection from the MyStore. -``` - -### recordOrCollection.getStore() - -Return the closest store. Used internally to resolve symbolic `~reference` relative to the store. - -Method looks for the `Store` subclass traversing the ownership chain of current aggregation tree upwards. If there are no store found this way, default Store from `Store.global` is returned. - -### recordOrCollection.clone({ pinStore : true }) - -Make the cloned object to preserve the reference to its original store. - -Cloned objects don't have an owner by default, thus they loose the reference to their store as no ownership chain can be traversed. `pinStore` option should be used in such a cases. \ No newline at end of file diff --git a/docs/chapters/observable.md b/docs/chapters/observable.md deleted file mode 100644 index df43fa4b..00000000 --- a/docs/chapters/observable.md +++ /dev/null @@ -1,325 +0,0 @@ -# Observable Changes - -## Overview - -Type-R implements *deeply observable changes* on the object graph constructed of records and collection. - -All of the record and collection updates happens in a scope of the transaction followed by the change event. Every record or collection update operation opens _implicit_ transaction. Several update operations can be groped to the single _explicit_ transaction if executed in the scope of the `obj.transaction()` or `col.updateEach()` call. - -```javascript -@define class Author extends Record { - static attributes = { - name : '' - } -} - -@define class Book extends Record { - static attributes = { - name : '', - datePublished : Date, - author : Author - } -} - -const book = new Book(); -book.on( 'change', () => console.log( 'Book is changed') ); - -// Implicit transaction, prints to the console -book.author.name = 'John Smith'; -``` - -## Record - -### Events mixin methods (7) - -Record implements [Events](#events-mixin) mixin. - -### `event` "change" ( record ) - -Triggered by the record at the end of the attributes update transaction in case if there were any changes applied. - -### `event` "change:attrName" ( record, value ) - -Triggered by the record during the attributes update transaction for every changed attribute. - -### `attrDef` : type( Type ).watcher( watcher ) - -Attach `change:attr` event listener to the particular record's attribute. `watcher` can either be the record's method name or the function `( newValue, attr ) => void`. Watcher is always executed in the context of the record. - -```javascript -@define class User extends Record { - static attributes = { - name : type( String ).watcher( 'onNameChange' ), - isAdmin : Boolean, - } - - onNameChange(){ - // Cruel. But we need it for the purpose of the example. - this.isAdmin = this.name.indexOf( 'Admin' ) >= 0; - } -} -``` - -### `attrDef` : type( Type ).changeEvents( false ) - -Turn off changes observation for nested records or collections. - -Record automatically listens to change events of all nested records and collections, triggering appropriate change events for its attributes. This declaration turns it off for the specific attribute. - -### `attrDef` : type( Type ).events({ eventName : handler, ... }) - -Automatically manage custom event subscription for the attribute. `handler` is either the method name or the handler function. - -### record.changed - -The `changed` property is the internal hash containing all the attributes that have changed during its last transaction. -Please do not update `changed` directly since its state is internally maintained by `set()`. -A copy of `changed` can be acquired from `changedAttributes()`. - -### record.changedAttributes( attrs? ) - -Retrieve a hash of only the record's attributes that have changed during the last transaction, -or false if there are none. Optionally, an external attributes hash can be passed in, -returning the attributes in that hash which differ from the record. -This can be used to figure out which portions of a view should be updated, -or what calls need to be made to sync the changes to the server. - -### record.previous( attr ) - -During a "change" event, this method can be used to get the previous value of a changed attribute. - -```javascript -@define class Person extends Record{ - static attributes = { - name: '' - } -} - -const bill = new Person({ - name: "Bill Smith" -}); - -bill.on("change:name", ( record, name ) => { - alert( `Changed name from ${ bill.previous('name') } to ${ name }`); -}); - -bill.name = "Bill Jones"; -``` - -### record.previousAttributes() - -Return a copy of the record's previous attributes. Useful for getting a diff between versions of a record, or getting back to a valid state after an error occurs. - -## Collection - -All changes in the records cause change events in the collections they are contained in. - -Subset collections is an exception; they don't observe changes of its elements by default. - -### Events mixin methods (7) - -Collection implements [Events](#events-mixin) mixin. - -### collection.transaction( fun ) - -Execute the sequence of updates in `fun` function in the scope of the transaction. - -All collection updates occurs in the scope of transactions. Transaction is the sequence of changes which results in a single `changes` event. - -Transaction can be opened either manually or implicitly with calling any of collection update methods. -Any additional changes made to the collection or its items in event handlers will be executed in the scope of the original transaction, and won't trigger an additional `changes` events. - -### collection.updateEach( iteratee : ( val : Record, index ) => void, context? ) - -Similar to the `collection.each`, but wraps an iteration in a transaction. The single `changes` event will be emitted for the group of changes to the records made in `updateEach`. - -### `static` itemEvents = { eventName : `handler`, ... } - -Subscribe for events from records. The `hander` is either the collection's method name, the handler function, or `true`. - -When `true` is passed as a handler, the corresponding event will be triggered on the collection. - -### `event` "changes" (collection, options) - -When collection has changed. Single event triggered when the collection has been changed. - -### `event` "reset" (collection, options) - -When the collection's entire contents have been reset (`reset()` method was called). - -### `event` "update" (collection, options) - -Single event triggered after any number of records have been added or removed from a collection. - -### `event` "sort" (collection, options) - -When the collection has been re-sorted. - -### `event` "add" (record, collection, options) - -When a record is added to a collection. - -### `event` "remove" (record, collection, options) - -When a record is removed from a collection. - -### `event` "change" (record, options) - -When a record inside of the collection is changed. - -## Events mixin - -Type-R uses an efficient synchronous events implementation which is backward compatible with Backbone 1.1 Events API but is about twice faster in all major browsers. It comes in form of `Events` mixin and the `Messenger` base class. - -`Events` is a [mixin](#mixins) giving the object the ability to bind and trigger custom named events. Events do not have to be declared before they are bound, and may take passed arguments. - -Both `source` and `listener` mentioned in method signatures must implement Events methods. - -```javascript -import { mixins, Events } from 'type-r' - -@mixins( Events ) -class EventfulClass { - ... -} -``` - - - -### source.trigger(event, arg1, arg2, ... ) - -Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks. - -### listener.listenTo(source, event, callback) -Tell an object to listen to a particular event on an other object. The advantage of using this form, instead of other.on(event, callback, object), is that listenTo allows the object to keep track of the events, and they can be removed all at once later on. The callback will always be called with object as context. - -```javascript - view.listenTo(record, 'change', view.render ); -``` - - - -### listener.stopListening([source], [event], [callback]) - -Tell an object to stop listening to events. Either call stopListening with no arguments to have the object remove all of its registered callbacks ... or be more precise by telling it to remove just the events it's listening to on a specific object, or a specific event, or just a specific callback. - -```javascript - view.stopListening(); // Unsubscribe from all events - - view.stopListening(record); // Unsubscribe from all events from the record -``` - - - -### listener.listenToOnce(source, event, callback) - -Just like `listenTo()`, but causes the bound callback to fire only once before being automatically removed. - -### source.on(event, callback, [context]) - -Bind a callback function to an object. The callback will be invoked whenever the event is fired. If you have a large number of different events on a page, the convention is to use colons to namespace them: `poll:start`, or `change:selection`. The event string may also be a space-delimited list of several events... - -```javascript - book.on("change:title change:author", ...); -``` - -Callbacks bound to the special "all" event will be triggered when any event occurs, and are passed the name of the event as the first argument. For example, to proxy all events from one object to another: - -```javascript - proxy.on("all", function(eventName) { - object.trigger(eventName); - }); -``` - -All event methods also support an event map syntax, as an alternative to positional arguments: - -```javascript - book.on({ - "change:author": authorPane.update, - "change:title change:subtitle": titleView.update, - "destroy": bookView.remove - }); -``` - -To supply a context value for this when the callback is invoked, pass the optional last argument: `record.on('change', this.render, this)` or `record.on({change: this.render}, this)`. - - - -### source.off([event], [callback], [context]) - -Remove a previously bound callback function from an object. If no context is specified, all of the versions of the callback with different contexts will be removed. If no callback is specified, all callbacks for the event will be removed. If no event is specified, callbacks for all events will be removed. - -```javascript - // Removes just the `onChange` callback. - object.off("change", onChange); - - // Removes all "change" callbacks. - object.off("change"); - - // Removes the `onChange` callback for all events. - object.off(null, onChange); - - // Removes all callbacks for `context` for all events. - object.off(null, null, context); - - // Removes all callbacks on `object`. - object.off(); -``` - -Note that calling `record.off()`, for example, will indeed remove all events on the record — including events that Backbone uses for internal bookkeeping. - -### source.once(event, callback, [context]) -Just like `on()`, but causes the bound callback to fire only once before being removed. Handy for saying "the next time that X happens, do this". When multiple events are passed in using the space separated syntax, the event will fire once for every event you passed in, not once for a combination of all events - -### Built-in events - -All Type-R objects implement Events mixin and use events to notify listeners on changes. - -Record and Store change events: - -Event name | Handler arguments | When triggered --------|-------------------|------------ -change | (record, options) | At the end of any changes. -change:attrName | (record, value, options) | The record's attribute has been changed. - -Collection change events: - -Event name | Handler arguments | When triggered --------|-------------------|------------ -changes | (collection, options) | At the end of any changes. -reset | (collection, options) | `reset()` method was called. -update | (collection, options) | Any records added or removed. -sort | (collection, options) | Order of records is changed. -add | (record, collection, options) | The record is added to a collection. -remove | (record, collection, options) | The record is removed from a collection. -change | (record, options) | The record is changed inside of collection. - -## Messenger class - -Messenger is an abstract base class implementing Events mixin and some convenience methods. - -```javascript -import { define, Messenger } from 'type-r' - -class MyMessenger extends Messenger { - -} -``` - -### Events mixin methods (7) - -Messenger implements [Events](#events-mixin) mixin. - -### messenger.cid - -Unique run-time only messenger instance id (string). - -### `callback` messenger.initialize() - -Callback which is called at the end of the constructor. - -### messenger.dispose() - -Executes `messenger.stopListening()` and `messenger.off()`. - -Objects must be disposed to prevent memory leaks caused by subscribing for events from singletons. \ No newline at end of file diff --git a/docs/chapters/record.md b/docs/chapters/record.md deleted file mode 100644 index 2bc57425..00000000 --- a/docs/chapters/record.md +++ /dev/null @@ -1,670 +0,0 @@ -# Record - -Record is an optionally persistent class having the predefined set of attributes. Each attribute is the property of known type which is protected from improper assigments at run-time, is serializable to JSON by default, has deeply observable changes, and may have custom validation rules attached. - -Records may have other records and collections of records stored in its attributes describing an application state of an arbitrary complexity. These nested records and collections are considered to be an integral part of the parent record forming an *aggregation tree* which can be serialized to JSON, cloned, and disposed of as a whole. - -All aspects of an attribute behavior are controlled with attribute metadata, which (taken together with its type) is called *attribite metatype*. Metatypes can be declared separately and reused across multiple records definitions. - -```javascript -import { define, type, Record } from 'type-r' - -// ⤹ required to make magic work -@define class User extends Record { - // ⤹ attribute's declaration - static attributes = { - firstName : '', // ⟵ String type is inferred from the default value - lastName : String, // ⟵ Or you can just mention its constructor - email : type(String).value(null), //⟵ Or you can provide both - createdAt : Date, // ⟵ And it works for any constructor. - // And you can attach ⤹ metadata to fine-tune attribute's behavior - lastLogin : type(Date).value(null).toJSON(false) // ⟵ not serializable - } -} - -const user = new User(); -console.log( user.createdAt ); // ⟵ this is an instance of Date created for you. - -const users = new User.Collection(); // ⟵ Collections are defined automatically. -users.on( 'changes', () => updateUI( users ) ); // ⟵ listen to the changes. - -users.set( json, { parse : true } ); // ⟵ parse raw JSON from the server. -users.updateEach( user => user.firstName = '' ); // ⟵ bulk update triggering 'changes' once -``` - -```typescript -import { define, attr, type, Record } from 'type-r' -import "reflect-metadata" // Required for @auto without arguments - -// ⤹ required to make the magic work -@define class User extends Record { - // ⤹ attribute's declaration - // IMPORTANT: attributes will be initialized even if no default value is provided. - @auto lastName : string // ⟵ @auto decorator extracts type from the Reflect metadata - @auto createdAt : Date // ⟵ It works for any constructor. - @auto('somestring') firstName : string //⟵ The custom default value must be passed to @auto decorator. - @auto(null) updatedAt : Date - - // You have to pass the type explicitly if reflect-metadata is not used. - @type(String).as email : string - - // Or, you can tell Type-R to infer type from the default value. - @value('').as email2 : string - - // Type cannot be inferred from null default values, and needs to be specified explicitly - @type(String).value(null).as email3 : string - - // You can attach ⤹ metadata to fine-tune attribute's behavior - @type(Date).toJSON(false).as - lastLogin : Date// ⟵ not serializable -} - -const user = new User(); -console.log(user.createdAt); // ⟵ this is an instance of Date created for you. - -const users : Collection = new User.Collection(); // ⟵ Collections are defined automatically. -users.on('changes', () => updateUI(users)); // ⟵ listen to the changes. - -users.set(json, { parse : true }); // ⟵ parse raw JSON from the server. -users.updateEach( user => user.firstName = '' ); // ⟵ bulk update triggering 'changes' once -``` - -## Definition - -Record definition is ES6 class extending `Record` preceeded by `@define` class decorator. - -Unlike in the majority of the JS state management framework, Record is not the key-value hash. Record has typed attributes with metadata controlling different aspects of attribute beavior. Therefore, developer needs to create the Record subclass to describe the data structure of specific shape, in a similar way as it's done in statically typed languages. The combination of an attribute type and metadata is called *metatype* and can be reused across record definitions. - -The minimal record definition looks like this: - -```javascript -@define class MyRecord extends Record { - static attributes = { - name : '' - } -} -``` - -```typescript -@define class MyRecord extends Record { - @auto name : string -} -``` - -### `static` attributes = { name : `attrDef`, ... } - -Record's attributes definition. Lists attribute names along with their types, default values, and metadata controlling different aspects of attribute behavior. - -```javascript -@define class User extends Record { - static attributes = { - name : type( String ).value( 'John Dow' ), - email : 'john.dow@mail.com', // Same as type( String ).value( 'john.dow@mail.com' ) - address : String, // Same as type( String ).value( '' ) - } -} -``` - -```typescript -// You should not use `static attributes` in TypeScript. Use decorators instead. -@define class User extends Record { - // Complete form of an attribute definition. - @type( String ).value( 'John Dow' ).as name : string, - - // Attribute type is inferred from the default value. - @value( 'john.dow@mail.com' ).as email : string , // Same as @type( String ).value( 'john.dow@mail.com' ).as - - // Attribute type is inferred from the TypeScript type declaration. - @auto address : string, // Same as @type( String ).value( '' ) - - // Same as above, but with a custom default value. - @auto( 'john.dow@mail.com' ) email2 : string // Same as @value( 'john.dow@mail.com' ).as -} - -``` - -The Record guarantee that _every attribute will retain the value of the declared type_. Whenever an attribute is being assigned with the value which is not compatible with its declared type, the type is being converted with an invocation of the constructor: `new Type( value )` (primitive types are treated specially). - -### `static` idAttribute = 'attrName' - -A record's unique identifier is stored under the pre-defined `id` attribute. -If you're directly communicating with a backend (CouchDB, MongoDB) that uses a different unique key, you may set a Record's `idAttribute` to transparently map from that key to id. - -Record's `id` property will still be linked to Record's id, no matter which value `idAttribute` has. - -```javascript -@define class Meal extends Record { - static idAttribute = "_id"; - static attributes = { - _id : Number, - name : '' - } -} - -const cake = new Meal({ _id: 1, name: "Cake" }); -alert("Cake id: " + cake.id); -``` -```typescript -@define class Meal extends Record { - static idAttribute = "_id"; - - @auto _id : number - @auto name : string -} - -const cake = new Meal({ _id: 1, name: "Cake" }); -alert("Cake id: " + cake.id); -``` - -### `attrDef` : Constructor - -Constructor function is the simplest form of attribute definition. Any constructor function which behaves as _converting constructor_ (like `new Date( msecs )`) may be used as an attribute type. - -```javascript -@define class Person extends Record { - static attributes = { - name : String, // String attribute which is "" by default. - createdAt : Date, // Date attribute - ... - } -} -``` - -```typescript -// In typescript, @auto decorator will extract constructor function from the TypeScript type -@define class Person extends Record { - @auto name : string // String attribute which is "" by default. - @auto createdAt : Date // Date attribute - - // Or, it can be specified explicitly with @type decorator. - @type( Date ).as updatedAt : Date // Date attribute - ... -} -``` - -### `attrDef` : defaultValue - -Any non-function value used as attribute definition is treated as an attribute's default value. Attribute's type is being inferred from the value. - -Type cannot be properly inferred from the `null` values and functions. -Use the general form of attribute definition in such cases: `value( theFunction )`, `type( Boolean ).value( null )`. - -```javascript -@define class GridColumn extends Record { - static attributes = { - name : '', // String attribute which is '' by default. - render : value( x => x ), // Infer Function type from the default value. - ... - } -} -``` - -```typescript -// In typescript, @value decorator will extract constructor function from the default value. -@define class GridColumn extends Record { - @value( '' ).as name : string // String attribute which is '' by default. - @value( x => x ).as render : Function - ... -} -``` - -### `attrDef` : type(Constructor).value(defaultValue) - -Declare an attribute with type T having the custom `defaultValue`. - -```javascript -@define class Person extends Record { - static attributes = { - phone : type( String ).value( null ) // String attribute which is null by default. - ... - } -} -``` - -```typescript -@define class Person extends Record { - @type( String ).value( null ).as phone : string // String attribute which is null by default. - - // There's an easy way of doing that in TypeScript. - @auto( null ).as phone : string - ... -} -``` - -If record needs to reference itself in its attributes definition, `@predefine` decorator with subsequent `MyRecord.define()` needs to be used. - -### `attrDef` : Date - -Date attribute initialized as `new Date()`, and represented in JSON as UTC ISO string. - -There are other popular Date serialization options available in `type-r/ext-types` package. - -* `MicrosoftDate` - Date serialized as Microsoft's `"/Date(msecs)/"` string. -* `Timestamp` - Date serializaed as UNIX integer timestamp (`date.getTime()`). - -```typescript -@define class Person extends Record { - @auto justDate : Date - // MicrosoftDate is an attribute metatype, not a real type, so you must pass it explictly. - @type( Timestamp ).as createdAt : Date - ... -} -``` - -### `static` Collection - -The default record's collection class automatically defined for every Record subclass. Can be referenced as `Record.Collection`. - -May be explicitly assigned in record's definition with custom collection class. - -```javascript -// Declare the collection class. -@define class Comments extends Record.Collection {} - -@define class Comment extends Record{ - static Collection = Comments; // Make it the default Comment collection. - - static attributes = { - text : String, - replies : Comments - } -} -``` - -```typescript -// Declare the collection class. -@define class Comments extends Collection {} - -@define class Comment extends Record{ - static Collection = Comments; // Make it the default Comment collection. - - @auto text : String - @auto replies : Comments -} -``` - -### `attrDef` type(Type) - -Attribute definition can have different metadata attached which affects various aspects of attribute's behavior. Metadata is attached with -a chain of calls after the `type( Ctor )` call. Attribute's default value is the most common example of such a metadata and is the single option which can be applied to the constructor function directly. - -```javascript -import { define, type, Record } - -@define class Dummy extends Record { - static attributes = { - a : type( String ).value( "a" ) - } -} -``` - -```typescript -import { define, type, Record } - -@define class Dummy extends Record { - @type( String ).value( "a" ).as a : string -} -``` - -## Definitions in TypeScript - -Type-R supports several options to define record attributes. - -### `decorator` @auto - -Turns TypeScript class property definition to the record's attribute, automatically extracting attribute type from the TypeScript type annotation. Requires `reflect-metadata` npm package and `emitDecoratorMetadata` option set to true in the `tsconfig.json`. - -`@auto` may take a single parameter as an attribute default value. No other attribute metadata can be attached. - -```typescript -import { define, auto, Record } from 'type-r' - -@define class User extends Record { - @auto name : string - @auto( "john@verizon.com" ) email : string - @auto( null ) updatedAt : Date -} -``` - -### `decorator` @`attrDef`.as - -Attribute definition creates the TypeScript property decorator when being appended with `.as` suffix. It's an alternative syntax to `@auto`. - -```typescript -import { define, type, Record } from 'type-r' - -@define class User extends Record { - @value( "5" ).as name : string - @type( String ).toJSON( false ).as email : string -} -``` - -## Create and dispose - -Record behaves as regular ES6 class with attributes accessible as properties. - -### new Record() - -Create an instance of the record with default attribute values taken from the attributes definition. - -When no default value is explicitly provided for an attribute, it's initialized as `new Type()` (just `Type()` for primitives). When the default value is provided and it's not compatible with the attribute type, it's converted with `new Type( defaultValue )` call. - -### new Record({ attrName : value, ... }, options?) - -When creating an instance of a record, you can pass in the initial attribute values to override the defaults. - -If `{parse: true}` option is used, `attrs` is assumed to be the JSON. - -If the value of the particular attribute is not compatible with its type, it's converted to the declared type invoking the constructor `new Type( value )` (just `Type( value )` for primitives). - -```javascript -@define class Book extends Record { - static attributes = { - title : '', - author : '' - } -} - -const book = new Book({ - title: "One Thousand and One Nights", - author: "Scheherazade" -}); -``` - -```typescript -@define class Book extends Record { - @auto title : string - @auto author : string -} - -const book = new Book({ - title: "One Thousand and One Nights", - author: "Scheherazade" -}); -``` - -### record.clone() - -Create the deep copy of the aggregation tree, recursively cloning all aggregated records and collections. References to shared members will be copied, but not shared members themselves. - -### `callback` record.initialize(attrs?, options?) - -Called at the end of the `Record` constructor when all attributes are assigned and the record's inner state is properly initialized. Takes the same arguments as -a constructor. - -### record.dispose() - -Recursively dispose the record and its aggregated members. "Dispose" means that elements of the aggregation tree will unsubscribe from all event sources. It's crucial to prevent memory leaks in SPA. - -The whole aggregation tree will be recursively disposed, shared members won't. - -## Read and Update - -### record.cid - -Read-only client-side record's identifier. Generated upon creation of the record and is unique for every record's instance. Cloned records will have different `cid`. - -### record.id - -Predefined record's attribute, the `id` is an arbitrary string (integer id or UUID). `id` is typically generated by the server. It is used in JSON for id-references. - -Records can be retrieved by `id` from collections, and there can be just one instance of the record with the same `id` in the particular collection. - -### record.isNew() - -Has this record been saved to the server yet? If the record does not yet have an `id`, it is considered to be new. - -### record.attrName - -Record's attributes may be directly accessed as `record.name`. - - - -```javascript -@define class Account extends Record { - static attributes = { - name : String, - balance : Number - } -} - -const myAccount = new Account({ name : 'mine' }); -myAccount.balance += 1000000; // That works. Good, eh? -``` - -### record.attrName = value - -Assign the record's attribute. If the value is not compatible with attribute's type from the declaration, it is converted: - -- with `Type( value )` call, for primitive types; -- with `record.attrName.set( value )`, for existing record or collection (updated in place); -- with `new Type( value )` in all other cases. - -Record triggers events on changes: -- `change:attrName` *( record, value )*. -- `change` *( record )*. - -```javascript -@define class Book extends Record { - static attributes = { - title : String, - author : String - price : Number, - publishedAt : Date, - available : Boolean - } -} - -const myBook = new Book({ title : "State management with Type-R" }); -myBook.author = 'Vlad'; // That works. -myBook.price = 'Too much'; // Converted with Number( 'Too much' ), resulting in NaN. -myBook.price = '123'; // = Number( '123' ). -myBook.publishedAt = new Date(); // Type is compatible, no conversion. -myBook.publishedAt = '1678-10-15 12:00'; // new Date( '1678-10-15 12:00' ) -myBook.available = some && weird || condition; // Will always be Boolean. Or null. -``` - -### record.set({ attrName : value, ... }, options? : `options`) - -Bulk assign record's attributes, possibly taking options. - -If the value is not compatible with attribute's type from the declaration, it is converted: - -- with `Type( value )` call, for primitive types. -- with `record.attrName.set( value )`, for existing record or collection (updated in place). -- with `new Type( value )` in all other cases. - -Record triggers events after all changes are applied: - -1. `change:attrName` *( record, val, options )* for any changed attribute. -2. `change` *(record, options)*, if there were changed attributes. - - -### RecordClass.from(attrs, options?) - -Create `RecordClass` from attributes. Similar to direct record creation, but supports additional option for strict data validation. -If `{ strict : true }` option is passed the validation will be performed and an exception will be thrown in case of an error. - -Please note, that Type-R always perform type checks on assignments, convert types, and reject improper updates reporting it as error. It won't, however, execute custom validation -rules on every updates as they are evaluated lazily. `strict` option will invoke custom validators and will throw on every error or warning instead of reporting them and continue. - -```javascript -// Fetch record with a given id. -const book = await Book.from({ id : 5 }).fetch(); - -// Validate the body of an incoming HTTP request. -// Throw an exception if validation fails. -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true }); -``` - -```typescript -// Fetch record with a given id. -const book = await Book.from({ id : 5 }).fetch(); - -// Validate the body of an incoming HTTP request. -// Throw an exception if validation fails. -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true }); -``` - -### record.assignFrom(otherRecord) - -Makes an existing `record` to be the full clone of `otherRecord`, recursively assigning all attributes. -In contracts to `record.clone()`, the record is updated in place. - -```javascript -// Another way of doing the bestSeller.clone() -const book = new Book(); -book.assignFrom(bestSeller); -``` - -### record.transaction(fun) - -Execute the all changes made to the record in `fun` as single transaction triggering the single `change` event. - -All record updates occurs in the scope of transactions. Transaction is the sequence of changes which results in a single `change` event. -Transaction can be opened either manually or implicitly with calling `set()` or assigning an attribute. -Any additional changes made to the record in `change:attr` event handler will be executed in the scope of the original transaction, and won't trigger additional `change` events. - - -```javascript -some.record.transaction( record => { - record.a = 1; // `change:a` event is triggered. - record.b = 2; // `change:b` event is triggered. -}); // `change` event is triggered. -``` - -Manual transactions with attribute assignments are superior to `record.set()` in terms of both performance and flexibility. - -### `attrDef` : type(Type).get(`hook`) - -Attach get hook to the record's attribute. `hook` is the function of signature `( value, attr ) => value` which is used to transform the attribute's value _before it will be read_. Hook is executed in the context of the record. - -### `attrDef` : type(Type).set(`hook`) - -Attach the set hook to the record's attribute. `hook` is the function of signature `( value, attr ) => value` which is used to transform the attribute's value _before it will be assigned_. Hook is executed in the context of the record. - -If set hook will return `undefined`, it will cancel attribute update. - -## Nested records and collections - -Record's attributes can hold other Records and Collections, forming indefinitely nested data structures of arbitrary complexity. -To create nested record or collection you should just mention its constructor function in attribute's definition. - -```javascript -import { Record } from 'type-r' - -@define class User extends Record { - static attributes = { - name : String, - email : String, - isActive : true - } -} - -@define class UsersListState extends Record { - static attributes = { - users : User.Collection - } -} -``` - -All nested records and collections are *aggregated* by default and behave as integral parts of the containing record. Aggregated attributes are _exclusively owned_ by the record, and taken with it together form an _ownership tree_. Many operations are performed recursively on aggregated elements: - -- They are created when the owner record is created. -- They are cloned when the record is cloned. -- They are disposed when the record is disposed. -- They are validated as part of the record. -- They are serialized as nested JSON. - -The nature of aggregation relationship in OO is explained in this [article](https://medium.com/@gaperton/nestedtypes-2-0-meet-an-aggregation-and-the-rest-of-oo-animals-a9fca7c36ecf). - -### `attrDef` : RecordOrCollection - -Aggregated record or collection. Represented as nested object or array in record's JSON. Aggregated members are owned by the record and treated as its _integral part_ (recursively created, cloned, serialized, validated, and disposed). -One object can have single owner. The record with its aggregated attributes forms an _aggregation tree_. - -All changes in aggregated record or collections are detected and cause change events on the containing record. - -### record.getOwner() - -Return the record which is an owner of the current record, or `null` there are no one. - -Due to the nature of _aggregation_, an object may have one and only one owner. - -### record.collection - -Return the collection which aggregates the record, or `null` if there are no one. - -### `attrDef` : shared(RecordOrCollection) - -Non-serializable reference to the record or collection possibly from the different aggregation tree. Initialized with `null`. Is not recursively cloned, serialized, validated, or disposed. - -All changes in shared records or collections are detected and cause change events of the containing record. - - - -```javascript -@define class UsersListState extends Record { - static attributes = { - users : User.Collection, - selected : shared( User ) // Can be assigned with the user from this.users - } -} -``` - -```typescript -@define class UsersListState extends Record { - @type( User.Collection ).as users : Collection, - @shared( User ).as selected : User // Can be assigned with the user from this.users -} -``` - -### `attrDef` : Collection.Refs - -Non-aggregating collection. Collection of references to shared records which itself is _aggregated_ by the record, but _does not aggregate_ its elements. In contrast to the `shared( Collection )`, `Collection.Refs` is an actual constructor and creates an instance of collection which _is the part the parent record_. - -The collection itself is recursively created and cloned. However, its records are not aggregated by the collection thus they are not recursively cloned, validated, serialized, or disposed. - -All changes in the collection and its elements are detected and cause change events of the containing record. - - - -```javascript - @define class MyRecord extends Record { - static attributes = { - notCloned : shared( SomeCollection ), // Reference to the _shared collection_ object. - cloned : SomeCollection.Refs // _Aggregated_ collection of references to the _shared records_. - } - } -``` - -```typescript - @define class MyRecord extends Record { - // Reference to the _shared collection_ object. - @shared( SomeCollection ).as notCloned : Collection - - // _Aggregated_ collection of references to the _shared records_. - @type( SomeCollection.Refs ).as cloned : SomeCollection - } -``` - -### `decorator` @predefine - -Make forward declaration for the record to define its attributes later with `RecordClass.define()`. Used instead of `@define` for recursive record definitions. - -Creates the default `RecordClass.Collection` type which can be referenced in attribute definitions. - -### `static` define({ attributes : { name : `attrDef`, ... }}) - -May be called to define attributes in conjunction with `@predefine` decorator to make recursive record definitions. - -```javascript -@predefine class Comment extends Record{} - -Comment.define({ - attributes : { - text : String, - replies : Comment.Collection - } -}); -``` diff --git a/docs/chapters/validation.md b/docs/chapters/validation.md deleted file mode 100644 index f159643d..00000000 --- a/docs/chapters/validation.md +++ /dev/null @@ -1,112 +0,0 @@ -# Type Safety and Validation - -Type-R records and collections are _dynamically type safe_. It's guaranteed that Type-R data structures will always conform to the declared shape. -Records and collections convert values to the declared types on assignment, and reject an update (logging an error in a console) if it cannot be done. - -In addition to that, Type-R supports validation API allowing developer to attach custom validation rules to attributes, records, and collections. Type-R validation mechanics based on following principles: - -- Validation happens transparently on the first access to the validation error. There's no special API to trigger the validation. -- Validation is performed recursively on the aggregation tree formed by nested records and collections. If an element at the bottom of the tree is not valid, the whole object tree is not valid. -- Validation results are cached across the aggregation tree, thus consequent validation error reads are cheap. Only changed parts of aggregation tree will be revalidated when necessary. - -## Attribute-level checks - -### `attrDef` : type( Type ).check( predicate, errorMsg? ) - -Attribute-level validator. - -- `predicate : value => boolean` is the function taking attribute's value and returning `true` whenever the value is valid. -- optional `errorMsg` is the error message which will be passed in case if the validation fail. - -If `errorMsg` is omitted, error message will be taken from `predicate.error`. It makes possible to define reusable validation functions. - -```javascript -function isAge( years ){ - return years >= 0 && years < 200; -} - -isAge.error = "Age must be between 0 and 200"; -``` - -Attribute may have any number of checks attached which are being executed in a sequence. Validation stops when first check in sequence fails. -It can be used to define reusable attribute types as demonstrated below: - -```javascript -// Define new attribute metatypes encapsulating validation checks. -const Age = type( Number ) - .check( x => x == null || x >= 0, 'I guess you are a bit older' ) - .check( x => x == null || x < 200, 'No way man can be that old' ); - -const Word = type( String ).check( x => indexOf( ' ' ) < 0, 'No spaces allowed' ); - -@define class Person extends Record { - static attributes = { - firstName : Word, - lastName : Word, - age : Age - } -} -``` - -### `attrDef` : type( Type ).required - -The special case of attribute-level check cutting out empty values. Attribute value must be truthy to pass, `"Required"` is used as validation error. - -`isRequired` is the first validator to check, no matter in which order validators were attached. - -## Record - -### rec.isValid( attrName ) - -Returns `true` if the specified record's attribute is valid. - -### rec.getValidationError( attrName ) - -Return the validation error for the given attribute or `null` if it's valid. - -## Record and Collection - -Record and Collection share the same validation API. `key` is the attribute name for the record and record's id/cid for the collection. - -### `callback` obj.validate() - -Override this method in subclass to define object-level validation rules. Whatever is returned from `validate()` is treated as validation error. - - - -### obj.isValid() - -Returns `true` if the object is valid. Has same effect as `!object.validationError`. - -### obj.isValid( key ) - -Returns `true` if the specified record's attribute or collection element is valid. `key` is an attribute's name for the record or record's id/cid for the collection. - -### obj.validationError - -`null` if an object is valid, or the the ValidationError object with detailed information on validation results. - -ValidationError object has following shape: - -```javascript -{ - error : /* as returned from collection.validate() */, - - // Members validation errors. - nested : { - // key is an attrName for the record, and record.cid for the collcation - key : validationError, - ... - } -} -``` - -### obj.getValidationError( key ) - -Return the validation error for the given attribute or collection's item. -`key` is an attribute's name for the record or record's id/cid for the collection. - -### obj.eachValidationError( iteratee : ( error, key, obj ) => void ) - -Recursively traverse aggregation tree validation errors. `key` is `null` for the object-level validation error returned by `obj.validate()`. -`obj` is the reference to the current object. \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index d9df2fdb..00000000 --- a/docs/index.html +++ /dev/null @@ -1,2359 +0,0 @@ - - - - - - - Type-R 3.0 API Reference - - - - - - - - - - - - - - - - - NAV - - - -
-
- -
-
Type-R 3.0
-
universal state management
-
- -
- - -
    -
    -
    - -
    -
    -
    -

    Getting started

    -

    Overview

    -

    Type-R is the TypeScript and JavaScript model framework helping to define and manage the complex application state as a combination of reusable parts. Type-R cover the needs of business logic and data layers in 3-tier application architecture, providing the presentation layer with the unified technique to handle the UI and domain state. Type-R data structures look and feel (and, in some aspects, behaves) more like classes in the statically typed languages.

    -

    Type-R in unopinionated on the way how an application state should be managed ("single source of truth" or "distributed state"). It can support all approaches equally well being not dependent on singletons and having powerful capabilities for state synchronization.

    -

    overview

    -

    A state is defined as a superposition of typed records and collections. A record is a class with a known set of attributes of predefined types possibly holding other records and collections in its attributes, describing the data structure of arbitrary complexity. Record with its attributes forms an aggregation tree with deeply observable attributes changes. Attribute types are checked on assignments and invalid changes are being rejected, therefore it is guaranteed that the application state will preserve the valid shape.

    -

    Application state defined with Type-R is serializable to JSON by default. Aggregation tree of records and collections is mapped in JSON as a tree of plain objects and arrays. Normalized data represented as a set of collections of records cross-referencing each other are supported as first-class serialization scenario.

    -

    A record may have an associated IOEndpont representing the I/O protocol for CRUD and collection fetch operations which enables the persistence API for the particular record/collection class pair. Some useful endpoints (restfulIO, localStorageIO, etc) are provided by type-r/endpoints/* packages, and developers can define their own I/O endpoints implementing any particular persistence transport or API.

    -

    Record attributes may have custom validation rules attached to them. Validation is being triggered transparently on demand and its result is cached across the record/collection aggregation tree, making subsequent calls to the validation API extremely cheap.

    -

    All aspects of record behavior including serialization and validation can be controlled on attribute level with declarative definitions combining attribute types with metadata. Attribute definitions ("metatypes") can be reused across different models forming the domain-specific language of model declarations. Some useful attribute metatypes (Email, Url, MicrosoftDate, etc) are provided by type-r/ext-types package.

    -

    How Type-R compares to X?

    -

    Type-R (former "NestedTypes") project was started in 2014 in Volicon as a modern successor to BackboneJS models, which would match Ember Data in its capabilities to work with a complex state while retaining the BackboneJS simplicity, modularity, and some degree of backward API compatibility. It replaced BackboneJS in the model layer of Volicon products, and it became the key technology in Volicon's strategy to gradually move from BackboneJS Views to React in the view layer.

    -

    Ember Data is the closest thing to Type-R by its capabilities, with BackboneJS models and collections being the closest thing by the API, and mobx being pretty close in the way how the UI state is managed.

    -

    Type-R, however, takes a very different approach to all of them:

    -
      -
    • Type-R models look and feel more like classes in a statically typed language with the majority of features being controlled by attribute metadata.
    • -
    • Type-R is built around the concept of aggregation trees formed by nested records and collections and it knows how to clone, serialize, and validate complex objects with cross-references properly.
    • -
    • In contrast to BackboneJS, Record is not an object hash but the class with statically typed and dynamically checked attributes.
    • -
    • In contrast to mobx, Type-R detects deeply nested changes.
    • -
    • In contrast to Ember Data, Type-R doesn't require the singleton global store. In Type-R, stores are a special kind of records and there might be as many dynamically created and disposed of stores as you need, starting with no stores at all.
    • -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FeatureType-RBackbone ModelsEmber Datamobx
    Observable changes in object graph--
    JSON Serialization-
    Validation-
    Dynamic Type Safety-for serialization only-
    Aggregation---
    Relations by id--
    Generalized I/Osync function-
    -

    Features by example

    -

    Here's the brief overview of features groped by application purpose.

    -

    Persistent domain state

    -

    The basic building block is the Record class. To fetch data from the server, a developer creates the subclass of the Record describing its attribute types and attaches the restfulIO endpoint. It enables the persistence API allowing the developer to fetch the collection from the server. restfulIO expects the server to implement the standard RESTful API expected by BackboneJS models.

    -
      -
    • GET /api/users - fetch all the users
    • -
    • POST /api/users - create the user
    • -
    • GET /api/users/:id - fetch the user with a given id
    • -
    • PUT /api/users/:id - update the user with a given id
    • -
    • DELETE /api/users/:id - delete the user with a given id
    • -
    -

    Record and collection are serializable to and can be parsed from JSON with no additional effort. A mapping to JSON can be customized for collections, records, and individual attributes. The Record validates all updates casting attribute values to declared attribute types to protect the state structure from the protocol incompatibilities and improper assignments.

    -
    @define User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -    static attributes = {
    -        name : String,
    -        email : String,
    -        createdAt : Date
    -    }
    -}
    -
    -const users = new User.Collection();
    -await users.fetch();
    -
    -expect( users.first().createdAt ).toBeInstanceOf( Date );
    -expect( typeof users.toJSON()[ 0 ].createdAt ).toBe( "string" );
    -
    -
    @define User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -
    -    // Type-R can infer attribute types from TypeScript type annotations.
    -    @auto name : string
    -    @auto email : string
    -    @auto createdAt : Date
    -}
    -
    -const users : Collection<User> = new User.Collection();
    -await users.fetch();
    -
    -expect( users.first().createdAt ).toBeInstanceOf( Date );
    -expect( typeof users.toJSON()[ 0 ].createdAt ).toBe( "string" );
    -
    -

    UI state and observable changes

    -

    Type-R provides the universal technique to working with the UI and domain state. To define the UI state, a developer creates the subclass of the Record with attributes holding all the necessary state data possibly along with the persistent data which can become the part of the same local UI state. The UI state itself can be a part of some particular view or UI component, it can be managed as a singleton ("single source of truth"), or both at the same time. Type-R is unopinionated on the application state structure leaving this decision to the developer.

    -

    Records and collections form an aggregation tree with deeply observable changes, so it's enough to subscribe to the single change event from the UIState to get updates on both data arrival and local changes of the state attributes. Records and collections can be indefinitely nested to describe a state of arbitrary complexity. The developer can attach reactions on changes to the records, their individual attributes, and collections. Additional changes made in reactions will be executed in the scope of the same "change transaction" and won't trigger additional change events.

    -
    @define UIState extends Record {
    -    static attributes = {
    -        users : User.Collection,
    -        selectedUser : memberOf( 'users' )
    -    }
    -}
    -
    -const uiState = new UIState();
    -
    -uiState.on( 'change', () => {
    -    console.log( 'Something is changed' );
    -    updateUI();
    -});
    -
    -uiState.users.fetch();
    -
    -
    @define UIState extends Record {
    -    // For collections and more complex types attribute type must be provided explicitly
    -    @type( User.Collection ).as users : Collection<User>
    -
    -    @memberOf( 'users' ).as selectedUser : User
    -}
    -
    -const uiState = new UIState();
    -
    -uiState.on( 'change', () => {
    -    console.log( 'Something is changed' );
    -    updateUI();
    -});
    -
    -uiState.users.fetch();
    -
    -

    Validation

    -

    Type-R supports validation as attribute-level checks attached to attribute definitions as metadata. Attribute type together with checks forms an "attribute metatype", which can be defined separately and reused across multiple record definitions.

    -

    Validation rules are evaluated recursively on the aggregation tree on first access to the validation API, and validations results are cached in records and collections across the tree till the next update. The validation is automatic, subsequent calls to the validation API are cheap, and the developer doesn't need to manually trigger the validation on data changes.

    -

    The majority of checks in a real application will be a part of attribute "metatypes", while the custom validation can be also defined on the Record and Collection level to check data integrity and cross-attributes dependencies.

    -
    const Email = type( String )
    -    .check( x => !x || x.indexOf( '@' ) >= 0, "Doesn't look like an email" );
    -
    -@define User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -    static attributes = {
    -        name : type( String ).required,
    -        email : type( Email ).required,
    -        createdAt : type( Date ).check( x => x.getTime() <= Date.now() )
    -    }
    -}
    -
    -const users = new User.Collection();
    -users.add({ email : 'john' });
    -expect( users.isValid() ).toBe( false );
    -expect( users.first().isValid() ).toBe( false );
    -
    -users.first().name = "John";
    -users.first().email = "john@ny.com";
    -expect( users.isValid() ).toBe( true );
    -
    -
    const Email = type( String )
    -    .check( x => !x || x.indexOf( '@' ) >= 0, "Doesn't look like an email" );
    -
    -@define User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -
    -    // @type(...).as converts Type-R attribute type definition to the TypeScript decorator.
    -    @type( String ).required.as
    -        name : string
    -
    -    @type( Email ).required.as
    -        email : string
    -
    -    @type( Date ).check( x => x.getTime() <= Date.now() ).as
    -        createdAt : Date
    -}
    -
    -const users = new User.Collection();
    -users.add({ email : 'john' });
    -expect( users.isValid() ).toBe( false );
    -expect( users.first().isValid() ).toBe( false );
    -
    -users.first().name = "John";
    -users.first().email = "john@ny.com";
    -expect( users.isValid() ).toBe( true );
    -
    -

    Installation and requirements

    -

    Is packed as UMD and ES6 module. No peer dependencies are required.

    -

    npm install type-r --save-dev

    - - - - -

    ReactJS bindings

    -

    React-MVx is a glue framework which uses Type-R to manage the UI state in React and the NestedLink library to implement two-way data binding. React-MVx provides the complete MVVM solution on top of ReactJS, featuring:

    - -

    Usage with NodeJS

    -

    Type-R can be used at the server side to build the business logic layer by defining the custom I/O endpoints to store data in a database. Type-R dynamic type safety features are particularly advantageous when schema-less JSON databases (like Couchbase) are being used.

    -

    server

    - -

    Record

    -

    Record is an optionally persistent class having the predefined set of attributes. Each attribute is the property of known type which is protected from improper assigments at run-time, is serializable to JSON by default, has deeply observable changes, and may have custom validation rules attached.

    -

    Records may have other records and collections of records stored in its attributes describing an application state of an arbitrary complexity. These nested records and collections are considered to be an integral part of the parent record forming an aggregation tree which can be serialized to JSON, cloned, and disposed of as a whole.

    -

    All aspects of an attribute behavior are controlled with attribute metadata, which (taken together with its type) is called attribite metatype. Metatypes can be declared separately and reused across multiple records definitions.

    -
    import { define, type, Record } from 'type-r'
    -
    -// ⤹ required to make magic work  
    -@define class User extends Record {
    -    // ⤹ attribute's declaration
    -    static attributes = {
    -        firstName : '', // ⟵ String type is inferred from the default value
    -        lastName  : String, // ⟵ Or you can just mention its constructor
    -        email     : type(String).value(null), //⟵ Or you can provide both
    -        createdAt : Date, // ⟵ And it works for any constructor.
    -        // And you can attach ⤹ metadata to fine-tune attribute's behavior
    -        lastLogin : type(Date).value(null).toJSON(false) // ⟵ not serializable
    -    }
    -}
    -
    -const user = new User();
    -console.log( user.createdAt ); // ⟵ this is an instance of Date created for you.
    -
    -const users = new User.Collection(); // ⟵ Collections are defined automatically.
    -users.on( 'changes', () => updateUI( users ) ); // ⟵ listen to the changes.
    -
    -users.set( json, { parse : true } ); // ⟵ parse raw JSON from the server.
    -users.updateEach( user => user.firstName = '' ); // ⟵ bulk update triggering 'changes' once
    -
    -
    import { define, attr, type, Record } from 'type-r'
    -import "reflect-metadata" // Required for @auto without arguments
    -
    -// ⤹ required to make the magic work  
    -@define class User extends Record {
    -    // ⤹ attribute's declaration
    -    // IMPORTANT: attributes will be initialized even if no default value is provided.
    -    @auto lastName  : string // ⟵ @auto decorator extracts type from the Reflect metadata
    -    @auto createdAt : Date // ⟵ It works for any constructor.
    -    @auto('somestring') firstName : string //⟵ The custom default value must be passed to @auto decorator.
    -    @auto(null) updatedAt : Date 
    -
    -    // You have to pass the type explicitly if reflect-metadata is not used.
    -    @type(String).as email : string
    -
    -    // Or, you can tell Type-R to infer type from the default value.
    -    @value('').as email2 : string
    -
    -    // Type cannot be inferred from null default values, and needs to be specified explicitly
    -    @type(String).value(null).as email3 : string 
    -
    -    // You can attach ⤹ metadata to fine-tune attribute's behavior
    -    @type(Date).toJSON(false).as
    -        lastLogin : Date// ⟵ not serializable
    -}
    -
    -const user = new User();
    -console.log(user.createdAt); // ⟵ this is an instance of Date created for you.
    -
    -const users : Collection<User> = new User.Collection(); // ⟵ Collections are defined automatically.
    -users.on('changes', () => updateUI(users)); // ⟵ listen to the changes.
    -
    -users.set(json, { parse : true }); // ⟵ parse raw JSON from the server.
    -users.updateEach( user => user.firstName = '' ); // ⟵ bulk update triggering 'changes' once
    -
    -

    Definition

    -

    Record definition is ES6 class extending Record preceeded by @define class decorator.

    -

    Unlike in the majority of the JS state management framework, Record is not the key-value hash. Record has typed attributes with metadata controlling different aspects of attribute beavior. Therefore, developer needs to create the Record subclass to describe the data structure of specific shape, in a similar way as it's done in statically typed languages. The combination of an attribute type and metadata is called metatype and can be reused across record definitions.

    -

    The minimal record definition looks like this:

    -
    @define class MyRecord extends Record {
    -    static attributes = {
    -        name : ''
    -    }
    -}
    -
    -
    @define class MyRecord extends Record {
    -    @auto name : string
    -}
    -
    -

    static attributes = { name : attrDef, ... }

    -

    Record's attributes definition. Lists attribute names along with their types, default values, and metadata controlling different aspects of attribute behavior.

    -
    @define class User extends Record {
    -    static attributes = {
    -        name    : type( String ).value( 'John Dow' ),
    -        email   : 'john.dow@mail.com', // Same as type( String ).value( 'john.dow@mail.com' )
    -        address : String, // Same as type( String ).value( '' )
    -    }
    -}
    -
    -
    // You should not use `static attributes` in TypeScript. Use decorators instead.
    -@define class User extends Record {
    -    // Complete form of an attribute definition.
    -    @type( String ).value( 'John Dow' ).as name : string,
    -
    -    // Attribute type is inferred from the default value.
    -    @value( 'john.dow@mail.com' ).as email : string , // Same as @type( String ).value( 'john.dow@mail.com' ).as
    -
    -    // Attribute type is inferred from the TypeScript type declaration.
    -    @auto address : string, // Same as @type( String ).value( '' )
    -
    -    // Same as above, but with a custom default value.
    -    @auto( 'john.dow@mail.com' ) email2 : string // Same as @value( 'john.dow@mail.com' ).as
    -}
    -
    -
    -

    The Record guarantee that every attribute will retain the value of the declared type. Whenever an attribute is being assigned with the value which is not compatible with its declared type, the type is being converted with an invocation of the constructor: new Type( value ) (primitive types are treated specially).

    -

    static idAttribute = 'attrName'

    -

    A record's unique identifier is stored under the pre-defined id attribute. -If you're directly communicating with a backend (CouchDB, MongoDB) that uses a different unique key, you may set a Record's idAttribute to transparently map from that key to id.

    -

    Record's id property will still be linked to Record's id, no matter which value idAttribute has.

    -
    @define class Meal extends Record {
    -  static idAttribute =  "_id";
    -  static attributes = {
    -      _id : Number,
    -      name : ''
    -  }
    -}
    -
    -const cake = new Meal({ _id: 1, name: "Cake" });
    -alert("Cake id: " + cake.id);
    -
    -
    @define class Meal extends Record {
    -  static idAttribute =  "_id";
    -
    -  @auto _id : number
    -  @auto name : string
    -}
    -
    -const cake = new Meal({ _id: 1, name: "Cake" });
    -alert("Cake id: " + cake.id);
    -
    -

    attrDef : Constructor

    -

    Constructor function is the simplest form of attribute definition. Any constructor function which behaves as converting constructor (like new Date( msecs )) may be used as an attribute type.

    -
    @define class Person extends Record {
    -    static attributes = {
    -        name : String, // String attribute which is "" by default.
    -        createdAt : Date, // Date attribute
    -        ...
    -    }
    -}
    -
    -
    // In typescript, @auto decorator will extract constructor function from the TypeScript type
    -@define class Person extends Record {
    -    @auto name : string // String attribute which is "" by default.
    -    @auto createdAt : Date // Date attribute
    -
    -    // Or, it can be specified explicitly with @type decorator.
    -    @type( Date ).as updatedAt : Date // Date attribute
    -    ...
    -}
    -
    -

    attrDef : defaultValue

    -

    Any non-function value used as attribute definition is treated as an attribute's default value. Attribute's type is being inferred from the value.

    -

    Type cannot be properly inferred from the null values and functions. -Use the general form of attribute definition in such cases: value( theFunction ), type( Boolean ).value( null ).

    -
    @define class GridColumn extends Record {
    -    static attributes = {
    -        name : '', // String attribute which is '' by default.
    -        render : value( x => x ), // Infer Function type from the default value.
    -        ...
    -    }
    -}
    -
    -
    // In typescript, @value decorator will extract constructor function from the default value.
    -@define class GridColumn extends Record {
    -    @value( '' ).as name : string // String attribute which is '' by default.
    -    @value( x => x ).as render : Function
    -    ...
    -}
    -
    -

    attrDef : type(Constructor).value(defaultValue)

    -

    Declare an attribute with type T having the custom defaultValue.

    -
    @define class Person extends Record {
    -    static attributes = {
    -        phone : type( String ).value( null ) // String attribute which is null by default.
    -        ...
    -    }
    -}
    -
    -
    @define class Person extends Record {
    -    @type( String ).value( null ).as phone : string // String attribute which is null by default.
    -
    -    // There's an easy way of doing that in TypeScript.
    -    @auto( null ).as phone : string
    -    ...
    -}
    -
    -

    If record needs to reference itself in its attributes definition, @predefine decorator with subsequent MyRecord.define() needs to be used.

    -

    attrDef : Date

    -

    Date attribute initialized as new Date(), and represented in JSON as UTC ISO string.

    -

    There are other popular Date serialization options available in type-r/ext-types package.

    -
      -
    • MicrosoftDate - Date serialized as Microsoft's "/Date(msecs)/" string.
    • -
    • Timestamp - Date serializaed as UNIX integer timestamp (date.getTime()).
    • -
    -
    @define class Person extends Record {
    -    @auto justDate : Date
    -    // MicrosoftDate is an attribute metatype, not a real type, so you must pass it explictly.
    -    @type( Timestamp ).as createdAt : Date
    -    ...
    -}
    -
    -

    static Collection

    -

    The default record's collection class automatically defined for every Record subclass. Can be referenced as Record.Collection.

    -

    May be explicitly assigned in record's definition with custom collection class.

    -
    // Declare the collection class.
    -@define class Comments extends Record.Collection {}
    -
    -@define class Comment extends Record{
    -    static Collection = Comments; // Make it the default Comment collection.
    -
    -    static attributes = {
    -        text : String,
    -        replies : Comments
    -    }
    -}
    -
    -
    // Declare the collection class.
    -@define class Comments extends Collection<Comment> {}
    -
    -@define class Comment extends Record{
    -    static Collection = Comments; // Make it the default Comment collection.
    -
    -    @auto text : String
    -    @auto replies : Comments
    -}
    -
    -

    attrDef type(Type)

    -

    Attribute definition can have different metadata attached which affects various aspects of attribute's behavior. Metadata is attached with -a chain of calls after the type( Ctor ) call. Attribute's default value is the most common example of such a metadata and is the single option which can be applied to the constructor function directly.

    -
    import { define, type, Record }
    -
    -@define class Dummy extends Record {
    -    static attributes = {
    -        a : type( String ).value( "a" )
    -    }
    -}
    -
    -
    import { define, type, Record }
    -
    -@define class Dummy extends Record {
    -    @type( String ).value( "a" ).as a : string
    -}
    -
    -

    Definitions in TypeScript

    -

    Type-R supports several options to define record attributes.

    -

    decorator @auto

    -

    Turns TypeScript class property definition to the record's attribute, automatically extracting attribute type from the TypeScript type annotation. Requires reflect-metadata npm package and emitDecoratorMetadata option set to true in the tsconfig.json.

    -

    @auto may take a single parameter as an attribute default value. No other attribute metadata can be attached.

    -
    import { define, auto, Record } from 'type-r'
    -
    -@define class User extends Record {
    -    @auto name : string
    -    @auto( "john@verizon.com" ) email : string
    -    @auto( null ) updatedAt : Date
    -}
    -
    -

    decorator @attrDef.as

    -

    Attribute definition creates the TypeScript property decorator when being appended with .as suffix. It's an alternative syntax to @auto.

    -
    import { define, type, Record } from 'type-r'
    -
    -@define class User extends Record {
    -    @value( "5" ).as name : string
    -    @type( String ).toJSON( false ).as email : string
    -}
    -
    -

    Create and dispose

    -

    Record behaves as regular ES6 class with attributes accessible as properties.

    -

    new Record()

    -

    Create an instance of the record with default attribute values taken from the attributes definition.

    -

    When no default value is explicitly provided for an attribute, it's initialized as new Type() (just Type() for primitives). When the default value is provided and it's not compatible with the attribute type, it's converted with new Type( defaultValue ) call.

    -

    new Record({ attrName : value, ... }, options?)

    -

    When creating an instance of a record, you can pass in the initial attribute values to override the defaults.

    -

    If {parse: true} option is used, attrs is assumed to be the JSON.

    -

    If the value of the particular attribute is not compatible with its type, it's converted to the declared type invoking the constructor new Type( value ) (just Type( value ) for primitives).

    -
    @define class Book extends Record {
    -    static attributes = {
    -        title  : '',
    -        author : ''
    -    }
    -}
    -
    -const book = new Book({
    -  title: "One Thousand and One Nights",
    -  author: "Scheherazade"
    -});
    -
    -
    @define class Book extends Record {
    -    @auto title : string
    -    @auto author : string
    -}
    -
    -const book = new Book({
    -  title: "One Thousand and One Nights",
    -  author: "Scheherazade"
    -});
    -
    -

    record.clone()

    -

    Create the deep copy of the aggregation tree, recursively cloning all aggregated records and collections. References to shared members will be copied, but not shared members themselves.

    -

    callback record.initialize(attrs?, options?)

    -

    Called at the end of the Record constructor when all attributes are assigned and the record's inner state is properly initialized. Takes the same arguments as -a constructor.

    -

    record.dispose()

    -

    Recursively dispose the record and its aggregated members. "Dispose" means that elements of the aggregation tree will unsubscribe from all event sources. It's crucial to prevent memory leaks in SPA.

    -

    The whole aggregation tree will be recursively disposed, shared members won't.

    -

    Read and Update

    -

    record.cid

    -

    Read-only client-side record's identifier. Generated upon creation of the record and is unique for every record's instance. Cloned records will have different cid.

    -

    record.id

    -

    Predefined record's attribute, the id is an arbitrary string (integer id or UUID). id is typically generated by the server. It is used in JSON for id-references.

    -

    Records can be retrieved by id from collections, and there can be just one instance of the record with the same id in the particular collection.

    -

    record.isNew()

    -

    Has this record been saved to the server yet? If the record does not yet have an id, it is considered to be new.

    -

    record.attrName

    -

    Record's attributes may be directly accessed as record.name.

    - - -
    @define class Account extends Record {
    -    static attributes = {
    -        name : String,
    -        balance : Number
    -    }
    -}
    -
    -const myAccount = new Account({ name : 'mine' });
    -myAccount.balance += 1000000; // That works. Good, eh?
    -
    -

    record.attrName = value

    -

    Assign the record's attribute. If the value is not compatible with attribute's type from the declaration, it is converted:

    -
      -
    • with Type( value ) call, for primitive types;
    • -
    • with record.attrName.set( value ), for existing record or collection (updated in place);
    • -
    • with new Type( value ) in all other cases.
    • -
    -

    Record triggers events on changes:

    -
      -
    • change:attrName ( record, value ).
    • -
    • change ( record ).
    • -
    -
    @define class Book extends Record {
    -    static attributes = {
    -        title : String,
    -        author : String
    -        price : Number,
    -        publishedAt : Date,
    -        available : Boolean
    -    }
    -}
    -
    -const myBook = new Book({ title : "State management with Type-R" });
    -myBook.author = 'Vlad'; // That works.
    -myBook.price = 'Too much'; // Converted with Number( 'Too much' ), resulting in NaN.
    -myBook.price = '123'; // = Number( '123' ).
    -myBook.publishedAt = new Date(); // Type is compatible, no conversion.
    -myBook.publishedAt = '1678-10-15 12:00'; // new Date( '1678-10-15 12:00' )
    -myBook.available = some && weird || condition; // Will always be Boolean. Or null.
    -
    -

    record.set({ attrName : value, ... }, options? : options)

    -

    Bulk assign record's attributes, possibly taking options.

    -

    If the value is not compatible with attribute's type from the declaration, it is converted:

    -
      -
    • with Type( value ) call, for primitive types.
    • -
    • with record.attrName.set( value ), for existing record or collection (updated in place).
    • -
    • with new Type( value ) in all other cases.
    • -
    -

    Record triggers events after all changes are applied:

    -
      -
    1. change:attrName ( record, val, options ) for any changed attribute.
    2. -
    3. change (record, options), if there were changed attributes.
    4. -
    -

    RecordClass.from(attrs, options?)

    -

    Create RecordClass from attributes. Similar to direct record creation, but supports additional option for strict data validation. -If { strict : true } option is passed the validation will be performed and an exception will be thrown in case of an error.

    -

    Please note, that Type-R always perform type checks on assignments, convert types, and reject improper updates reporting it as error. It won't, however, execute custom validation -rules on every updates as they are evaluated lazily. strict option will invoke custom validators and will throw on every error or warning instead of reporting them and continue.

    -
    // Fetch record with a given id.
    -const book = await Book.from({ id : 5 }).fetch();
    -
    -// Validate the body of an incoming HTTP request.
    -// Throw an exception if validation fails.
    -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true });
    -
    -
    // Fetch record with a given id.
    -const book = await Book.from({ id : 5 }).fetch();
    -
    -// Validate the body of an incoming HTTP request.
    -// Throw an exception if validation fails.
    -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true });
    -
    -

    record.assignFrom(otherRecord)

    -

    Makes an existing record to be the full clone of otherRecord, recursively assigning all attributes. -In contracts to record.clone(), the record is updated in place.

    -
    // Another way of doing the bestSeller.clone()
    -const book = new Book();
    -book.assignFrom(bestSeller);
    -
    -

    record.transaction(fun)

    -

    Execute the all changes made to the record in fun as single transaction triggering the single change event.

    -

    All record updates occurs in the scope of transactions. Transaction is the sequence of changes which results in a single change event. -Transaction can be opened either manually or implicitly with calling set() or assigning an attribute. -Any additional changes made to the record in change:attr event handler will be executed in the scope of the original transaction, and won't trigger additional change events.

    -
    some.record.transaction( record => {
    -    record.a = 1; // `change:a` event is triggered.
    -    record.b = 2; // `change:b` event is triggered.
    -}); // `change` event is triggered.
    -
    -

    Manual transactions with attribute assignments are superior to record.set() in terms of both performance and flexibility.

    -

    attrDef : type(Type).get(hook)

    -

    Attach get hook to the record's attribute. hook is the function of signature ( value, attr ) => value which is used to transform the attribute's value before it will be read. Hook is executed in the context of the record.

    -

    attrDef : type(Type).set(hook)

    -

    Attach the set hook to the record's attribute. hook is the function of signature ( value, attr ) => value which is used to transform the attribute's value before it will be assigned. Hook is executed in the context of the record.

    -

    If set hook will return undefined, it will cancel attribute update.

    -

    Nested records and collections

    -

    Record's attributes can hold other Records and Collections, forming indefinitely nested data structures of arbitrary complexity. -To create nested record or collection you should just mention its constructor function in attribute's definition.

    -
    import { Record } from 'type-r'
    -
    -@define class User extends Record {
    -    static attributes = {
    -        name : String,
    -        email : String,
    -        isActive : true
    -    }
    -}
    -
    -@define class UsersListState extends Record {
    -    static attributes = {
    -        users : User.Collection
    -    }
    -}
    -
    -

    All nested records and collections are aggregated by default and behave as integral parts of the containing record. Aggregated attributes are exclusively owned by the record, and taken with it together form an ownership tree. Many operations are performed recursively on aggregated elements:

    -
      -
    • They are created when the owner record is created.
    • -
    • They are cloned when the record is cloned.
    • -
    • They are disposed when the record is disposed.
    • -
    • They are validated as part of the record.
    • -
    • They are serialized as nested JSON.
    • -
    -

    The nature of aggregation relationship in OO is explained in this article.

    -

    attrDef : RecordOrCollection

    -

    Aggregated record or collection. Represented as nested object or array in record's JSON. Aggregated members are owned by the record and treated as its integral part (recursively created, cloned, serialized, validated, and disposed). -One object can have single owner. The record with its aggregated attributes forms an aggregation tree.

    -

    All changes in aggregated record or collections are detected and cause change events on the containing record.

    -

    record.getOwner()

    -

    Return the record which is an owner of the current record, or null there are no one.

    -

    Due to the nature of aggregation, an object may have one and only one owner.

    -

    record.collection

    -

    Return the collection which aggregates the record, or null if there are no one.

    -

    attrDef : shared(RecordOrCollection)

    -

    Non-serializable reference to the record or collection possibly from the different aggregation tree. Initialized with null. Is not recursively cloned, serialized, validated, or disposed.

    -

    All changes in shared records or collections are detected and cause change events of the containing record.

    - - -
    @define class UsersListState extends Record {
    -    static attributes = {
    -        users : User.Collection,
    -        selected : shared( User ) // Can be assigned with the user from this.users
    -    }
    -}
    -
    -
    @define class UsersListState extends Record {
    -    @type( User.Collection ).as users : Collection<User>,
    -    @shared( User ).as selected : User // Can be assigned with the user from this.users
    -}
    -
    -

    attrDef : Collection.Refs

    -

    Non-aggregating collection. Collection of references to shared records which itself is aggregated by the record, but does not aggregate its elements. In contrast to the shared( Collection ), Collection.Refs is an actual constructor and creates an instance of collection which is the part the parent record.

    -

    The collection itself is recursively created and cloned. However, its records are not aggregated by the collection thus they are not recursively cloned, validated, serialized, or disposed.

    -

    All changes in the collection and its elements are detected and cause change events of the containing record.

    - - -
        @define class MyRecord extends Record {
    -        static attributes = {
    -            notCloned : shared( SomeCollection ), // Reference to the _shared collection_ object.
    -            cloned : SomeCollection.Refs // _Aggregated_ collection of references to the _shared records_.
    -        }
    -    }
    -
    -
        @define class MyRecord extends Record {
    -        // Reference to the _shared collection_ object.
    -        @shared( SomeCollection ).as notCloned : Collection<Some>
    -
    -        // _Aggregated_ collection of references to the _shared records_.
    -        @type( SomeCollection.Refs ).as cloned : SomeCollection
    -    }
    -
    -

    decorator @predefine

    -

    Make forward declaration for the record to define its attributes later with RecordClass.define(). Used instead of @define for recursive record definitions.

    -

    Creates the default RecordClass.Collection type which can be referenced in attribute definitions.

    -

    static define({ attributes : { name : attrDef, ... }})

    -

    May be called to define attributes in conjunction with @predefine decorator to make recursive record definitions.

    -
    @predefine class Comment extends Record{}
    -
    -Comment.define({
    -    attributes : {
    -        text : String,
    -        replies : Comment.Collection
    -    }
    -});
    -
    -

    Collection

    -

    Collections are ordered sets of records. The collection is an array-like object exposing ES6 Array and BackboneJS Collection interface. It encapsulates JS Array of records (collection.models) and a hashmap for a fast O(1) access by the record id and cid (collection.get( id )).

    -

    Collactions are deeply observable. You can bind "changes" events to be notified when the collection has been modified, listen for the record "add", "remove", and "change" events.

    -

    Every Record class has an implicitly defined Collection accessible as a static member of a record's constructor. In a most cases, you don't need to define the custom collection class.

    -
    @define class Book extends Record {
    -    static attributes = {
    -        title : String
    -        author : Author
    -    }
    -}
    -
    -// Implicitly defined collection.
    -const books = new Book.Collection();
    -
    -
    @define class Book extends Record {
    -    @auto title : string
    -    @auto author : Author
    -
    -    // Tell TypeScript the proper type.
    -    static Collection : CollectionConstructor<Book>
    -}
    -
    -const books = new Book.Collection();
    -
    -

    You can define custom collection classes extending Record.Collection or any other collection class. It can either replace the default Collection type, or

    -
    // Define custom collection class.
    -@define class Library extends Record.Collection {
    -    doSomething(){ ... }
    -}
    -
    -@define class Book extends Record {
    -    // Override the default collection.
    -    static Collection = Library;
    -}
    -
    -// Define another custom collection class.
    -@define class OtherLibrary extends Record.Collection {
    -    // Specify the record so the collection will be able to restore itself from JSON.
    -    static model = Book; 
    -}
    -
    -
    // Define custom collection class.
    -@define class Library extends Collection<Book> {
    -    doSomething(){ ... }
    -}
    -
    -@define class Book extends Record {
    -    // Override the default collection.
    -    static Collection = Library;
    -}
    -
    -// Define another custom collection class.
    -@define class OtherLibrary extends Collection<Book> {
    -    // Specify the record so the collection will be able to restore itself from JSON.
    -    static model = Book;
    -}
    -
    -// An alternative way of overriding the default collection class in TypeScript.
    -namespace Book {
    -    @define class Collection extends Collection<Book> {
    -        static model = Book;
    -    }
    -}
    -
    - - -

    Collection types

    -

    constructor CollectionClass( records?, options? )

    -

    The most common collection type is an aggregating serializable collection. By default, collection aggregates its elements which are treated as an integral part of the collection (serialized, cloned, disposed, and validated recursively). An aggregation means the single owner, as the single object cannot be an integral part of two distinct things. The collection will take ownership on its records and will put an error in the console if it can't.

    -

    When creating a Collection, you may choose to pass in the initial array of records.

    -
    @define class Role extends Record {
    -    static attributes = {
    -        name : String
    -    }
    -}
    -
    -const roles = new Role.Collection( json, { parse : true } );
    -
    -
    @define class Role extends Record {
    -    // In typescript, you have to specify record's Collection type expicitly.
    -    static Collection : CollectionConstructor<Role>
    -
    -    @auto name : string
    -}
    -
    -@define class User extends Record {
    -    @auto name : string
    -
    -    // Type-R cannot infer a Collection metatype from the TypeScript type automatically.
    -    // Full attribute type annotation is required.
    -    @type( Role.Collection ).as roles : Collection<User>
    -}
    -
    -

    constructor CollectionClass.Refs( records?, options? )

    -

    Collection of record references is a non-aggregating non-serializable collection. Collection.Refs doesn't aggregate its elements, which means that containing records are not considered as an integral part of the enclosing collection and not being validated, cloned, disposed, and serialized recursively.

    -

    It is useful for a local non-persistent application state.

    -

    attrDef subsetOf(masterRef, CollectionClass?)

    -

    The subset of other collections are non-aggregating serializable collection. Subset-of collection is serialized as an array of record ids and used to model many-to-many relationships. The collection object itself is recursively created and cloned, however, its records are not aggregated by the collection thus they are not recursively cloned, validated, or disposed. CollectionClass argument may be omitted unless you need the record's attribute to be an instance of the particular collection class.

    - - - - -

    Must have a reference to the master collection which is used to resolve record ids to records. masterRef may be:

    -
      -
    • direct reference to a singleton collection.
    • -
    • function, returning the reference to the collection.
    • -
    • symbolic dot-separated path to the master collection resolved relative to the record's this. You may use owner and store macro in path:
        -
      • owner is the reference to the record's owner. owner.some.path works as () => this.getOwner().some.path.
      • -
      • store is the reference to the closes store. store.some.path works as () => this.getStore().some.path.
      • -
      -
    • -
    -
    @define class Role extends Record {
    -    static attributes = {
    -        name : String,
    -        ...
    -    }
    -}
    -
    -@define class User extends Record {
    -    static attributes = {
    -        name : String,
    -        roles : subsetOf( 'owner.roles', Role.Collection )
    -    }
    -}
    -
    -@define class UsersDirectory extends Store {
    -    static attributes = {
    -        roles : Role.Collection,
    -        users : User.Collection // `~roles` references will be resolved against this.roles
    -    }
    -}
    -
    -
    @define class Role extends Record {
    -    static Collection : CollectionConstructor<Role>
    -
    -    @auto name : string
    -    ...
    -}
    -
    -@define class User extends Record {
    -    static Collection : CollectionConstructor<User>
    -
    -    @auto name : string
    -    @subsetOf('store.roles').as roles : Collection<Role>
    -}
    -
    -@define class UsersDirectory extends Store {
    -    @type(Role.Collection).as roles : Collection<Role>,
    -    @type(User.Collection).as users : Collection<User> // <- `store.roles` references will be resolved against this.roles
    -}
    -
    -

    Array API

    -

    A collection class is an array-like object implementing ES6 Array methods and properties.

    -

    collection.length

    -

    Like an array, a Collection maintains a length property, counting the number of records it contains.

    -

    collection.slice( begin, end )

    -

    Return a shallow copy of the collection.models, using the same options as native Array#slice.

    -

    collection.indexOf( recordOrId : any ) : number

    -

    Return an index of the record in the collection, and -1 if there is no such a record in the collection.

    -

    Can take the record itself as an argument, id, or cid of the record.

    -

    collection.forEach( iteratee : ( val : Record, index ) => void, context? )

    -

    Iterate through the elements of the collection.

    - - -

    collection.map( iteratee : ( val : Record, index ) => T, context? )

    -

    Map elements of the collection. Similar to Array.map.

    -

    collection.filter( iteratee : Predicate, context? )

    -

    Return the filtered array of records matching the predicate.

    -

    The predicate is either the iteratee function returning boolean, or an object with attribute values used to match with record's attributes.

    -

    collection.every( iteratee : Predicate, context? ) : boolean

    -

    Return true if all records match the predicate.

    -

    collection.some( iteratee : Predicate, context? ) : boolean

    -

    Return true if at least one record matches the predicated.

    -

    collection.push( record, options? )

    -

    Add a record at the end of a collection. Takes the same options as add().

    -

    collection.pop( options? )

    -

    Remove and return the last record from a collection. Takes the same options as remove().

    -

    collection.unshift( record, options? )

    -

    Add a record at the beginning of a collection. Takes the same options as add().

    -

    collection.shift( options? )

    -

    Remove and return the first record from a collection. Takes the same options as remove().

    -

    Backbone API

    -

    Common options used by Backbone API methods:

    -
      -
    • { sort : false } - do not sort the collection.
    • -
    • { parse : true } - parse raw JSON (used to set collection with data from the server).
    • -
    -

    callback collection.initialize( records?, options? )

    -

    Initialization function which is called at the end of the constructor.

    -

    collection.clone()

    -

    Clone the collection. An aggregating collection will be recursively cloned, non-aggregated collections will be shallow cloned.

    -

    collection.models

    -

    Raw access to the JavaScript array of records inside of the collection. Usually, you'll want to use get, at, or the other methods to access record objects, but occasionally a direct reference to the array is desired.

    -

    collection.get( id )

    -

    Get a record from a collection, specified by an id, a cid, or by passing in a record.

    -
    const book = library.get(110);
    -
    -

    collection.at( index )

    -

    Get a record from a collection, specified by index. Useful if your collection is sorted, and if your collection isn't sorted, at will still retrieve records in insertion order. When passed a negative index, it will retrieve the record from the back of the collection.

    -

    collection.add( records, options? )

    -

    Add a record (or an array of records) to the collection. If this is the Record.Collection, you may also pass raw attributes objects, and have them be vivified as instances of the Record. Returns the added (or preexisting, if duplicate) records.

    -

    Pass {at: index} to splice the record into the collection at the specified index. If you're adding records to the collection that are already in the collection, they'll be ignored, unless you pass {merge: true}, in which case their attributes will be merged into the corresponding records.

    -
      -
    1. Trigger the one event per record:
        -
      • add(record, collection, options) for each record added.
      • -
      • change(record, options) for each record changed (if the {merge: true} option is passed).
      • -
      -
    2. -
    3. Trigger the single event:
        -
      • update(collection, options) if any records were added.
      • -
      • sort(collection, options) if an order of records was changed.
      • -
      -
    4. -
    5. Trigger changes event in case if any changes were made to the collection and objects inside.
    6. -
    -

    collection.remove( records, options? )

    -

    Remove a record (or an array of records) from the collection, and return them. Each record can be a record instance, an id string or a JS object, any value acceptable as the id argument of collection.get.

    -
      -
    1. Trigger remove(record, collection, options) for each record removed.
    2. -
    3. If any records were removed, trigger:
        -
      • update(collection, options)
      • -
      • changes(collection, options).
      • -
      -
    4. -
    -

    collection.set( records, options? )

    -

    The set method performs a "smart" update of the collection with the passed list of records. If a record in the list isn't yet in the collection it will be added; if the record is already in the collection its attributes will be merged; and if the collection contains any records that aren't present in the list, they'll be removed. All of the appropriate "add", "remove", and "change" events are fired as this happens. Returns the touched records in the collection. If you'd like to customize the behavior, you can disable it with options: {remove: false}, or {merge: false}.

    -

    Events

    -
      -
    1. Trigger the one event per record:
        -
      • add(record, collection, options) for each record added.
      • -
      • remove(record, collection, options) for each record removed.
      • -
      • change(record, options) for each record changed.
      • -
      -
    2. -
    3. Trigger the single event:
        -
      • update(collection, options) if any records were added.
      • -
      • sort(collection, options) if an order of records was changed.
      • -
      -
    4. -
    5. Trigger changes event in case if any changes were made to the collection and objects inside.
    6. -
    -
    const vanHalen = new Man.Collection([ eddie, alex, stone, roth ]);
    -
    -vanHalen.set([ eddie, alex, stone, hagar ]);
    -
    -// Fires a "remove" event for roth, and an "add" event for hagar.
    -// Updates any of stone, alex, and eddie's attributes that may have
    -// changed over the years.
    -
    -

    collection.reset(records, options?)

    -

    Replace the collection's content with the new records. More efficient than collection.set, but does not send record-level events.

    -

    Calling collection.reset() without passing any records as arguments will empty the entire collection.

    -
      -
    1. Trigger event reset(collection, options).
    2. -
    3. Trigger event changes(collection, options).
    4. -
    -

    collection.pluck(attribute)

    -

    Pluck an attribute from each model in the collection. Equivalent to calling map and returning a single attribute from the iterator.

    -
    const users = new UserCollection([
    -  {name: "Curly"},
    -  {name: "Larry"},
    -  {name: "Moe"}
    -]);
    -
    -const names = users.pluck("name");
    -
    -alert(JSON.stringify(names));
    -
    -

    Sorting

    -

    Type-R implements BackboneJS Collection sorting API with some extensions.

    -

    collection.sort(options?)

    -

    Force a collection to re-sort itself. You don't need to call this under normal circumstances, as a collection with a comparator will sort itself whenever a record is added. To disable sorting when adding a record, pass {sort: false} to add. Calling sort triggers a "sort" event on the collection.

    -

    By default, there is no comparator for a collection. If you define a comparator, it will be used to maintain the collection in sorted order. This means that as records are added, they are inserted at the correct index in collection.models.

    -

    Note that Type-R depends on the arity of your comparator function to determine between the two styles, so be careful if your comparator function is bound.

    -

    Collections with a comparator will not automatically re-sort if you later change record attributes, so you may wish to call sort after changing record attributes that would affect the order.

    -

    static comparator = 'attrName'

    -

    Maintain the collection in sorted order by the given record's attribute.

    -

    static comparator = x => number | string

    -

    Maintain the collection in sorted order according to the "sortBy" comparator function.

    -

    "sortBy" comparator functions take a record and return a numeric or string value by which the record should be ordered relative to others.

    -

    static comparator = (x, y) => -1 | 0 | 1

    -

    Maintain the collection in sorted order according to the "sort" comparator function.

    -

    "sort" comparator functions take two records and return -1 if the first record should come before the second, 0 if they are of the same rank and 1 if the first record should come after.

    -

    Note how even though all of the chapters in this example are added backward, they come out in the proper order:

    -
    @define class Chapter extends Record {
    -    static attributes = {
    -        page : Number,
    -        title : String
    -    }
    -}
    -
    -var chapters = new Chapter.Collection();
    -
    -chapters.comparator = 'page';
    -
    -chapters.add({page: 9, title: "The End"});
    -chapters.add({page: 5, title: "The Middle"});
    -chapters.add({page: 1, title: "The Beginning"});
    -
    -alert(chapters.map( x => x.title ));
    -
    -

    Other methods

    -

    CollectionClass.from( models, options? )

    -

    Create CollectionClass from the array of models. Similar to direct collection creation, but supports additional option for strict data validation. -If { strict : true } option is passed the validation will be performed and an exception will be thrown in case of an error.

    -

    Please note, that Type-R always performs type checks on assignments, convert types, and reject improper updates reporting it as an error. It won't, however, execute custom validation -rules on every update as they are evaluated lazily. strict option will invoke custom validators and will throw on every error or warning instead of reporting them and continue.

    -
    // Validate the body of an incoming HTTP request.
    -// Throw an exception if validation fails.
    -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true });
    -
    -
    // Validate the body of an incoming HTTP request.
    -// Throw an exception if validation fails.
    -const body = MyRequestBody.from( ctx.request.body, { parse : true, strict : true });
    -
    -

    collection.createSubset( records?, options? )

    -

    Create the collection which is a subset of a source collection serializable as an array of record ids. Takes the same arguments as the collection's constructor.

    -

    The created collection is an instance of subsetOf( sourceCollection, CollectionCtor ) attribute type (non-aggregating serializable collection).

    - - -

    collection.assignFrom( otherCollection )

    -

    Synchronize the state of the collection and its aggregation tree with other collection of the same type. Updates existing objects in place. Record in the collection is considered to be "existing" if it has the same id.

    -

    Equivalent to collection.set( otherCollection.models, { merge : true } ) and triggers similar events on change.

    -

    collection.dispose()

    -

    Dispose of the collection. An aggregating collection will recursively dispose of its records.

    -

    Observable Changes

    -

    Overview

    -

    Type-R implements deeply observable changes on the object graph constructed of records and collection.

    -

    All of the record and collection updates happens in a scope of the transaction followed by the change event. Every record or collection update operation opens implicit transaction. Several update operations can be groped to the single explicit transaction if executed in the scope of the obj.transaction() or col.updateEach() call.

    -
    @define class Author extends Record {
    -    static attributes = {
    -        name : ''
    -    }
    -}
    -
    -@define class Book extends Record {
    -    static attributes = {
    -        name : '',
    -        datePublished : Date,
    -        author : Author
    -    }
    -}
    -
    -const book = new Book();
    -book.on( 'change', () => console.log( 'Book is changed') );
    -
    -// Implicit transaction, prints to the console
    -book.author.name = 'John Smith';
    -
    -

    Record

    -

    Events mixin methods (7)

    -

    Record implements Events mixin.

    -

    event "change" ( record )

    -

    Triggered by the record at the end of the attributes update transaction in case if there were any changes applied.

    -

    event "change:attrName" ( record, value )

    -

    Triggered by the record during the attributes update transaction for every changed attribute.

    -

    attrDef : type( Type ).watcher( watcher )

    -

    Attach change:attr event listener to the particular record's attribute. watcher can either be the record's method name or the function ( newValue, attr ) => void. Watcher is always executed in the context of the record.

    -
    @define class User extends Record {
    -    static attributes = {
    -        name : type( String ).watcher( 'onNameChange' ),
    -        isAdmin : Boolean,
    -    }
    -
    -    onNameChange(){
    -        // Cruel. But we need it for the purpose of the example.
    -        this.isAdmin = this.name.indexOf( 'Admin' ) >= 0;
    -    }
    -}
    -
    -

    attrDef : type( Type ).changeEvents( false )

    -

    Turn off changes observation for nested records or collections.

    -

    Record automatically listens to change events of all nested records and collections, triggering appropriate change events for its attributes. This declaration turns it off for the specific attribute.

    -

    attrDef : type( Type ).events({ eventName : handler, ... })

    -

    Automatically manage custom event subscription for the attribute. handler is either the method name or the handler function.

    -

    record.changed

    -

    The changed property is the internal hash containing all the attributes that have changed during its last transaction. -Please do not update changed directly since its state is internally maintained by set(). -A copy of changed can be acquired from changedAttributes().

    -

    record.changedAttributes( attrs? )

    -

    Retrieve a hash of only the record's attributes that have changed during the last transaction, -or false if there are none. Optionally, an external attributes hash can be passed in, -returning the attributes in that hash which differ from the record. -This can be used to figure out which portions of a view should be updated, -or what calls need to be made to sync the changes to the server.

    -

    record.previous( attr )

    -

    During a "change" event, this method can be used to get the previous value of a changed attribute.

    -
    @define class Person extends Record{
    -    static attributes = {
    -        name: ''
    -    }
    -}
    -
    -const bill = new Person({
    -  name: "Bill Smith"
    -});
    -
    -bill.on("change:name", ( record, name ) => {
    -  alert( `Changed name from ${ bill.previous('name') } to ${ name }`);
    -});
    -
    -bill.name = "Bill Jones";
    -
    -

    record.previousAttributes()

    -

    Return a copy of the record's previous attributes. Useful for getting a diff between versions of a record, or getting back to a valid state after an error occurs.

    -

    Collection

    -

    All changes in the records cause change events in the collections they are contained in.

    -

    Subset collections is an exception; they don't observe changes of its elements by default.

    -

    Events mixin methods (7)

    -

    Collection implements Events mixin.

    -

    collection.transaction( fun )

    -

    Execute the sequence of updates in fun function in the scope of the transaction.

    -

    All collection updates occurs in the scope of transactions. Transaction is the sequence of changes which results in a single changes event.

    -

    Transaction can be opened either manually or implicitly with calling any of collection update methods. -Any additional changes made to the collection or its items in event handlers will be executed in the scope of the original transaction, and won't trigger an additional changes events.

    -

    collection.updateEach( iteratee : ( val : Record, index ) => void, context? )

    -

    Similar to the collection.each, but wraps an iteration in a transaction. The single changes event will be emitted for the group of changes to the records made in updateEach.

    -

    static itemEvents = { eventName : handler, ... }

    -

    Subscribe for events from records. The hander is either the collection's method name, the handler function, or true.

    -

    When true is passed as a handler, the corresponding event will be triggered on the collection.

    -

    event "changes" (collection, options)

    -

    When collection has changed. Single event triggered when the collection has been changed.

    -

    event "reset" (collection, options)

    -

    When the collection's entire contents have been reset (reset() method was called).

    -

    event "update" (collection, options)

    -

    Single event triggered after any number of records have been added or removed from a collection.

    -

    event "sort" (collection, options)

    -

    When the collection has been re-sorted.

    -

    event "add" (record, collection, options)

    -

    When a record is added to a collection.

    -

    event "remove" (record, collection, options)

    -

    When a record is removed from a collection.

    -

    event "change" (record, options)

    -

    When a record inside of the collection is changed.

    -

    Events mixin

    -

    Type-R uses an efficient synchronous events implementation which is backward compatible with Backbone 1.1 Events API but is about twice faster in all major browsers. It comes in form of Events mixin and the Messenger base class.

    -

    Events is a mixin giving the object the ability to bind and trigger custom named events. Events do not have to be declared before they are bound, and may take passed arguments.

    -

    Both source and listener mentioned in method signatures must implement Events methods.

    -
    import { mixins, Events } from 'type-r'
    -
    -@mixins( Events )
    -class EventfulClass {
    -    ...
    -}
    -
    - - -

    source.trigger(event, arg1, arg2, ... )

    -

    Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks.

    -

    listener.listenTo(source, event, callback)

    -

    Tell an object to listen to a particular event on an other object. The advantage of using this form, instead of other.on(event, callback, object), is that listenTo allows the object to keep track of the events, and they can be removed all at once later on. The callback will always be called with object as context.

    -
        view.listenTo(record, 'change', view.render );
    -
    - - -

    listener.stopListening([source], [event], [callback])

    -

    Tell an object to stop listening to events. Either call stopListening with no arguments to have the object remove all of its registered callbacks ... or be more precise by telling it to remove just the events it's listening to on a specific object, or a specific event, or just a specific callback.

    -
        view.stopListening(); // Unsubscribe from all events
    -
    -    view.stopListening(record); // Unsubscribe from all events from the record
    -
    - - -

    listener.listenToOnce(source, event, callback)

    -

    Just like listenTo(), but causes the bound callback to fire only once before being automatically removed.

    -

    source.on(event, callback, [context])

    -

    Bind a callback function to an object. The callback will be invoked whenever the event is fired. If you have a large number of different events on a page, the convention is to use colons to namespace them: poll:start, or change:selection. The event string may also be a space-delimited list of several events...

    -
        book.on("change:title change:author", ...);
    -
    -

    Callbacks bound to the special "all" event will be triggered when any event occurs, and are passed the name of the event as the first argument. For example, to proxy all events from one object to another:

    -
        proxy.on("all", function(eventName) {
    -        object.trigger(eventName);
    -    });
    -
    -

    All event methods also support an event map syntax, as an alternative to positional arguments:

    -
        book.on({
    -        "change:author": authorPane.update,
    -        "change:title change:subtitle": titleView.update,
    -        "destroy": bookView.remove
    -    });
    -
    -

    To supply a context value for this when the callback is invoked, pass the optional last argument: record.on('change', this.render, this) or record.on({change: this.render}, this).

    - - -

    source.off([event], [callback], [context])

    -

    Remove a previously bound callback function from an object. If no context is specified, all of the versions of the callback with different contexts will be removed. If no callback is specified, all callbacks for the event will be removed. If no event is specified, callbacks for all events will be removed.

    -
        // Removes just the `onChange` callback.
    -    object.off("change", onChange);
    -
    -    // Removes all "change" callbacks.
    -    object.off("change");
    -
    -    // Removes the `onChange` callback for all events.
    -    object.off(null, onChange);
    -
    -    // Removes all callbacks for `context` for all events.
    -    object.off(null, null, context);
    -
    -    // Removes all callbacks on `object`.
    -    object.off();
    -
    -

    Note that calling record.off(), for example, will indeed remove all events on the record — including events that Backbone uses for internal bookkeeping.

    -

    source.once(event, callback, [context])

    -

    Just like on(), but causes the bound callback to fire only once before being removed. Handy for saying "the next time that X happens, do this". When multiple events are passed in using the space separated syntax, the event will fire once for every event you passed in, not once for a combination of all events

    -

    Built-in events

    -

    All Type-R objects implement Events mixin and use events to notify listeners on changes.

    -

    Record and Store change events:

    - - - - - - - - - - - - - - - - - - - - -
    Event nameHandler argumentsWhen triggered
    change(record, options)At the end of any changes.
    change:attrName(record, value, options)The record's attribute has been changed.
    -

    Collection change events:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Event nameHandler argumentsWhen triggered
    changes(collection, options)At the end of any changes.
    reset(collection, options)reset() method was called.
    update(collection, options)Any records added or removed.
    sort(collection, options)Order of records is changed.
    add(record, collection, options)The record is added to a collection.
    remove(record, collection, options)The record is removed from a collection.
    change(record, options)The record is changed inside of collection.
    -

    Messenger class

    -

    Messenger is an abstract base class implementing Events mixin and some convenience methods.

    -
    import { define, Messenger } from 'type-r'
    -
    -class MyMessenger extends Messenger {
    -
    -}
    -
    -

    Events mixin methods (7)

    -

    Messenger implements Events mixin.

    -

    messenger.cid

    -

    Unique run-time only messenger instance id (string).

    -

    callback messenger.initialize()

    -

    Callback which is called at the end of the constructor.

    -

    messenger.dispose()

    -

    Executes messenger.stopListening() and messenger.off().

    -

    Objects must be disposed to prevent memory leaks caused by subscribing for events from singletons.

    -

    Type Safety and Validation

    -

    Type-R records and collections are dynamically type safe. It's guaranteed that Type-R data structures will always conform to the declared shape. -Records and collections convert values to the declared types on assignment, and reject an update (logging an error in a console) if it cannot be done.

    -

    In addition to that, Type-R supports validation API allowing developer to attach custom validation rules to attributes, records, and collections. Type-R validation mechanics based on following principles:

    -
      -
    • Validation happens transparently on the first access to the validation error. There's no special API to trigger the validation.
    • -
    • Validation is performed recursively on the aggregation tree formed by nested records and collections. If an element at the bottom of the tree is not valid, the whole object tree is not valid.
    • -
    • Validation results are cached across the aggregation tree, thus consequent validation error reads are cheap. Only changed parts of aggregation tree will be revalidated when necessary.
    • -
    -

    Attribute-level checks

    -

    attrDef : type( Type ).check( predicate, errorMsg? )

    -

    Attribute-level validator.

    -
      -
    • predicate : value => boolean is the function taking attribute's value and returning true whenever the value is valid.
    • -
    • optional errorMsg is the error message which will be passed in case if the validation fail.
    • -
    -

    If errorMsg is omitted, error message will be taken from predicate.error. It makes possible to define reusable validation functions.

    -
    function isAge( years ){
    -    return years >= 0 && years < 200;
    -}
    -
    -isAge.error = "Age must be between 0 and 200";
    -
    -

    Attribute may have any number of checks attached which are being executed in a sequence. Validation stops when first check in sequence fails. -It can be used to define reusable attribute types as demonstrated below:

    -
    // Define new attribute metatypes encapsulating validation checks.
    -const Age = type( Number )
    -                .check( x => x == null || x >= 0, 'I guess you are a bit older' )
    -                .check( x => x == null || x < 200, 'No way man can be that old' );
    -
    -const Word = type( String ).check( x => indexOf( ' ' ) < 0, 'No spaces allowed' );
    -
    -@define class Person extends Record {
    -    static attributes = {
    -        firstName : Word,
    -        lastName : Word,
    -        age : Age
    -    }
    -}
    -
    -

    attrDef : type( Type ).required

    -

    The special case of attribute-level check cutting out empty values. Attribute value must be truthy to pass, "Required" is used as validation error.

    -

    isRequired is the first validator to check, no matter in which order validators were attached.

    -

    Record

    -

    rec.isValid( attrName )

    -

    Returns true if the specified record's attribute is valid.

    -

    rec.getValidationError( attrName )

    -

    Return the validation error for the given attribute or null if it's valid.

    -

    Record and Collection

    -

    Record and Collection share the same validation API. key is the attribute name for the record and record's id/cid for the collection.

    -

    callback obj.validate()

    -

    Override this method in subclass to define object-level validation rules. Whatever is returned from validate() is treated as validation error.

    - - -

    obj.isValid()

    -

    Returns true if the object is valid. Has same effect as !object.validationError.

    -

    obj.isValid( key )

    -

    Returns true if the specified record's attribute or collection element is valid. key is an attribute's name for the record or record's id/cid for the collection.

    -

    obj.validationError

    -

    null if an object is valid, or the the ValidationError object with detailed information on validation results.

    -

    ValidationError object has following shape:

    -
    {
    -    error : /* as returned from collection.validate() */,
    -
    -    // Members validation errors.
    -    nested : {
    -        // key is an attrName for the record, and record.cid for the collcation
    -        key : validationError,
    -        ...
    -    }
    -}
    -
    -

    obj.getValidationError( key )

    -

    Return the validation error for the given attribute or collection's item. -key is an attribute's name for the record or record's id/cid for the collection.

    -

    obj.eachValidationError( iteratee : ( error, key, obj ) => void )

    -

    Recursively traverse aggregation tree validation errors. key is null for the object-level validation error returned by obj.validate(). -obj is the reference to the current object.

    -

    I/O and Serialization

    -

    Overview

    -

    Type-R implements generalized IO on top of the IOEndpoint interface, with JSON serialization handled by Record and Collection classes.

    -

    IOEndpoint defines the set of CRUD + list methods operating on raw JSON. -Attachment of an endpoint to the record or collection enables I/O API. There are few endpoints bundled with Type-R, for instance memoryIO() which can be used for mock testing.

    -
    @define class User extends Record {
    -    static endpoint = memoryIO();
    -
    -    static attributes = {
    -        name : '',
    -        email : ''
    -    }
    -}
    -
    -const users = new User.Collection();
    -users
    -    .add({ name : 'John' })
    -    .save()
    -    .then( () => console.log( user.id );
    -
    -

    I/O API

    -

    static endpoint

    -

    I/O endpoint declaration which should be used in Record or Collection definition to enable I/O API.

    -

    If an endpoint is defined for the MyRecord, it's automatically defined for the corresponding MyRecord.Collection as well.

    -

    attrDef : type( Type ).endpoint( endpoint )

    -

    Override or define an I/O endpoint for the specific record's attribute.

    -

    obj.getEndpoint()

    -

    Returns an object's IO endpoint. Normally, this is an endpoint which is defined in object's static endpoint = ... declaration, but it might be overridden by the parent's record using type( Type ).endpoint( ... ) attribute declaration.

    -
    @define class User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -    ...
    -}
    -
    -@define class UserRole extends Record {
    -    static endpoint = restfulIO( '/api/roles' );
    -    static attributes = {
    -        // Use the relative path '/api/roles/:id/users'
    -        users : type( User.Collection ).endpoint( restfulIO( './users' ) ),
    -        ...
    -    }
    -}
    -
    -

    record.fetch( options? )

    -

    Asynchronously fetch the record using endpoint.read() method. Returns an abortable ES6 promise.

    -

    An endpoint must be defined for the record in order to use that method.

    -

    record.save( options? )

    -

    Asynchronously save the record using endpoint.create() (if there are no id) or endpoint.update() (if id is present) method. Returns an abortable ES6 promise.

    -

    An endpoint must be defined for the record in order to use that method.

    -

    record.destroy( options? )

    -

    Asynchronously destroy the record using endpoint.destroy() method. Returns an abortable ES6 promise. The record is removed from the aggregating collection upon the completion of the I/O request.

    -

    An endpoint must be defined for the record in order to use that method.

    -

    collection.fetch( options? )

    -

    Fetch the collection. Returns an abortable promise.

    -

    options accepts an optional liveUpdates parameter. When true, collection subscribes for the live updates when I/O is finished.

    -

    collection.liveUpdates( true | false )

    -

    Subscribe for the live data updates if an I/O endpoint supports it (subscribe()/unsubscribe() IOEndpoint methods).

    - - -

    obj.hasPendingIO()

    -

    Returns an abortable promise if there's any I/O pending with the object, or null otherwise.

    -

    Can be used to check for active I/O in progress or to abort pending I/O operation. Please note, that all pending I/O is aborted automatically when new I/O operation is started or an object is disposed. When I/O is aborted, the promise is rejected.

    -
    const promise = users.hasPendingIO();
    -if( promise && promise.abort ) promise.abort();
    -
    -

    I/O endpoints

    -

    restfulIO( url, options? )

    -

    HTTP REST client endpoint. Requires window.fetch available natively or through the polyfill. Implements standard BackboneJS REST semantic.

    -

    All I/O methods append an optional options.params object to the URL parameters translating them to string with JSON.stringify().

    -
      -
    • record.save() makes:
        -
      • POST url, if the model has no id. Expects to receive { id : recordId }.
      • -
      • PUT url/:id, if the model has an id.
      • -
      -
    • -
    • collection.fetch() makes GET url.
    • -
    • record.destroy() makes DELETE url.
    • -
    -

    Supports URI relative to owner (./relative/url resolves as /owner/:id/relative/url/:id ).

    -
    import { restfulIO } from 'type-r/endpoints/restful'
    -
    -@define class Role extends Record {
    -    static endpoint = restfulIO( '/api/roles' );
    -    ...
    -}
    -
    -@define class User extends Record {
    -    static endpoint = restfulIO( '/api/users' );
    -
    -    static attributes = {
    -        // Roles collection here has relative url /api/users/:user_id/roles/
    -        roles : type( Role.Collection ).endpoint( restfulIO( './roles' ) ), 
    -        ...
    -    }
    -}
    -
    -

    memoryIO( mockData?, delay? )

    -

    Endpoint for mock testing. Takes optional array with mock data, and optional delay parameter which is the simulated I/O delay in milliseconds.

    -
    import { memoryIO } from 'type-r/endpoints/memory'
    -
    -@define class User extends Record {
    -    static endpoint = memoryIO();
    -    ...
    -}
    -
    -

    localStorageIO( key )

    -

    Endpoint for localStorage. Takes key parameter which must be unique for the persistent record's collection.

    -
    import { localStorageIO } from 'type-r/endpoints/localStorage'
    -
    -@define class User extends Record {
    -    static endpoint = localStorageIO( '/users' );
    -    ...
    -}
    -
    -

    attributesIO()

    -

    Endpoint for I/O composition. Redirects record's fetch() request to its attributes and returns the combined abortable promise. Does not enable any other I/O methods and can be used with record.fetch() only.

    -

    It's common pattern to use attributesIO endpoint in conjunction with Store to fetch all the data required by SPA page.

    -
    import { localStorageIO } from 'type-r/endpoints/attributes'
    -
    -@define class PageStore extends Store {
    -    static endpoint = attributesIO();
    -    static attributes = {
    -        users : User.Collection,
    -        roles : UserRole.Collection,
    -    }
    -}
    -...
    -const store = new PageStore();
    -store.fetch().then( () => renderUI() );
    -
    -

    proxyIO( RecordCtor )

    -

    Create IO endpoint from the Record class. This endpoint is designed for use on the server side with a data layer managed by Type-R.

    -

    Assuming that you have Type-R records with endpoints working with the database, you can create an endpoint which will use -an existing Record subclass as a transport. This endpoint can be connected to the RESTful endpoint API on the server side which will serve JSON to the restfulIO endpoint on the client.

    -

    An advantage of this approach is that JSON schema will be transparently validated on the server side by the Type-R.

    -
        import { proxyIO } from 'type-r/endpoint/proxy'
    -
    -    ...
    -
    -    const usersIO = proxyIO( User );
    -
    -

    IOEndpoint Interface

    -

    An IO endpoint is an "plug-in" abstraction representing the persistent collection of JSON objects, which is required to enable records and collections I/O API. There are several pre-defined endpoints included in Type-R package which can be used for HTTP REST I/O, mock testing, working with localStorage, and IO composition.

    -

    You will need to define custom endpoint if you would like to implement or customize serialization transport for Type-R objects. Use built-in endpoints as an example and the starting boilerplate.

    -

    All IOEndpoint methods might return standard Promises or abortable promises (created with createIOPromise()). An IOEndpoint instance is shared by all of the class instances it's attached to and therefore it's normally must be stateless.

    -

    endpoint.read( id, options, record )

    -

    Reads an object with a given id. Used by record.fetch() method. Must return JSON wrapped in abortable promise.

    -

    endpoint.update( id, json, options, record )

    -

    Updates or creates an object with a given id. Used by record.save() method when record already has an id. Must return abortable promise.

    -

    endpoint.create( json, options, record )

    -

    Creates an object. Used by record.save() method when record does not have an id. Must return abortable promise.

    -

    endpoint.destroy( id, options, record )

    -

    Destroys the object with the given id. Used by record.destroy() method. Must return abortable promise.

    -

    endpoint.list( options, collection )

    -

    Fetch an array of objects. Used by collection.fetch() method. Must returns abortable promise.

    -

    endpoint.subscribe( callbacks, collection )

    -

    Optional method to enable the live updates subscription. Used by collection.liveUpdates( true ) method. Must returns abortable promise.

    -

    Method callbacks argument is an object of the following shape:

    -
    {
    -    // Endpoint must call it when an object is created or updated.
    -    updated( json ){}
    -
    -    // Endpoint must call it when an object is removed.
    -    removed( json ){}
    -}
    -
    -

    endpoint.unsubscribe( callbacks, collection )

    -

    Unsubscribe from the live updates. Used by collection.liveUpdates( false ) method. Takes the same callbacks object as subscribe().

    -

    createIOPromise( init )

    -

    Service function to create an abortable version of ES6 promise (with promise.abort() which meant to stop pending I/O and reject the promise).

    -

    init function takes the third onAbort argument to register an optional abort handler. If no handler is registered, the default implementation of promise.abort() will just reject the promise.

    -
    import { createIOPromise } from 'type-r'
    -
    -const abortablePromise = createIOPromise( ( resolve, reject, onAbort ) =>{
    -    ...
    -    onAbort( () => {
    -        reject( 'I/O Aborted' );
    -    });
    -});
    -
    -

    Serialization

    -

    Record and Collection has a portion of common API related to the I/O and serialization.

    -

    obj.toJSON( options? )

    -

    Serialize record or collection to JSON. Used internally by save() I/O method (options.ioMethod === 'save' when called from within save()). Can be overridden to customize serialization.

    -

    Produces the JSON for the given record or collection and its aggregated members. Aggregation tree is serialized as nested JSON. Record corresponds to an object in JSON, while the collection is represented as an array of objects.

    -

    If you override toJSON(), it usually means that you must override parse() as well, and vice versa.

    - - -
    @define class Comment extends Record {
    -    static attributes = {
    -        body : ''
    -    }
    -}
    -
    -@define class BlogPost extends Record {
    -    static attributes = {
    -        title : '',
    -        body : '',
    -        comments : Comment.Collection
    -    }
    -}
    -
    -const post = new BlogPost({
    -    title: "Type-R is cool!",
    -    comments : [ { body : "Agree" }]
    -});
    -
    -const rawJSON = post.toJSON()
    -// { title : "Type-R is cool!", body : "", comments : [{ body : "Agree" }] }
    -
    -

    option { parse : true }

    -

    obj.set() and constructor's option to force parsing of the raw JSON. Is used internally by I/O methods to parse the data received from the server.

    -
    // Another way of doing the bestSeller.clone()
    -// Amazingly, this is guaranteed to work by default.
    -const book = new Book();
    -book.set( bestSeller.toJSON(), { parse : true } );
    -
    -

    callback obj.parse( json, options? )

    -

    Optional hook called to transform the JSON when it's passes to the record or collection with set( json, { parse : true }) call. Used internally by I/O methods (options.ioMethod is either "save" or "fetch" when called from I/O method).

    -

    If you override toJSON(), it usually means that you must override parse() as well, and vice versa.

    - - -

    attrDef : type( Type ).toJSON( false )

    -

    Do not serialize the specific attribute.

    -

    attrDef : type( Type ).toJSON( ( value, name, options ) => json )

    -

    Override the default serialization for the specific record's attribute.

    -

    Attribute is not serialized when the function return undefined.

    -

    attrDef : type( Type ).parse( ( json, name ) => value )

    -

    Transform the data before it will be assigned to the record's attribute.

    -

    Invoked when the { parse : true } option is set.

    -
    // Define custom boolean attribute type which is serialized as 0 or 1.
    -const MyWeirdBool = type( Boolean )
    -                      .parse( x => x === 1 )
    -                      .toJSON( x => x ? 1 : 0 );
    -
    -

    static create( attrs, options )

    -

    Static factory function used internally by Type-R to create instances of the record.

    -

    May be redefined in the abstract Record base class to make it serializable type.

    -
    @define class Widget extends Record {
    -    static attributes = {
    -        type : String
    -    }
    -
    -    static create( attrs, options ){
    -        switch( attrs.type ){
    -            case "typeA" : return new TypeA( attrs, options );
    -            case "typeB" : return new TypeB( attrs, options );
    -        }
    -    }
    -}
    -
    -@define class TypeA extends Widget {
    -    static attributes = {
    -        type : "typeA",
    -        ...
    -    }
    -}
    -
    -@define class TypeB extends Widget {
    -    static attributes = {
    -        type : "typeB",
    -        ...
    -    }
    -}
    -
    -

    Normalized data

    -

    Type-R has first-class support for working with normalized data represented as a set of collections with cross-references by record id. References are represented as record ids in JSON, and being transparently resolved to record instances on the first access.

    -

    Store class is the special record class which serves as a placeholder for the set of interlinked collections of normalized records. Id-references are defined as record attributes of the special type representing the serializable reference to the records from the specified master collection.

    -

    attrDef : memberOf( sourceCollection )

    -

    Serializable reference to the record from the particular collection. -Initialized as null and serialized as record.id. Is not recursively cloned, validated, or disposed. Used to model one-to-many relationships.

    -

    Changes in shared record are not detected.

    -

    sourceCollection may be:

    -
      -
    • the JS variable pointing to the collection singleton;
    • -
    • the function returning the collection;
    • -
    • the string with the dot-separated relative object path to the collection. It is resolved dynamically relative to the record's this. Following shortcuts may be used in path:
        -
      • owner.path (or ^path) works as () => this.getOwner().path.
      • -
      • store.path (or ~path) works as () => this.getStore().path.
      • -
      -
    • -
    -
        @define class State extends Record {
    -        static attributes = {
    -            items : Item.Collection,
    -            selected : memberOf( 'items' ) // Will resolve to `this.items`
    -        }
    -    }
    -
    -
        @define class State extends Record {
    -        @type( Item.Collection ).as items : Collection<Item>;
    -        @memberOf( 'items' ).as selected : Item
    -    }
    -
    - - -

    attrDef : subsetOf( sourceCollection, CollectionCtor? )

    -

    Serializable non-aggregating collection which is the subset of the existing collection. Serialized as an array of record ids. Used to model many-to-many relationships. CollectionCtor argument may be omitted unless you need it to be a sublass of the particular collection type.

    -

    The collection object itself is recursively created and cloned. However, its records are not aggregated by the collection thus they are not recursively cloned, validated, or disposed.

    -

    sourceCollection is the same reference as used by memberOf( sourceCollection ).

    -
    @define class Role extends Record {
    -    static attributes = {
    -        name : String,
    -        ...
    -    }
    -}
    -
    -@define class User extends Record {
    -    static attributes = {
    -        name : String,
    -        roles : subsetOf( '~roles', Role.Collection )
    -    }
    -}
    -
    -@define class UsersDirectory extends Store {
    -    static attributes = {
    -        roles : Role.Collection,
    -        users : User.Collection // `~roles` references will be resolved against this.roles
    -    }
    -}
    -
    -

    sourceCollection.createSubset( records?, options? )

    -

    Create an instance of subsetOf( sourceCollection, CollectionCtor ) type (non-aggregating serializable collection) which is the subset of the given collection. Takes the same arguments as the collection's constructor.

    - - -

    class Store

    -

    Store is the special kind of record which serves as a root for id references.

    -

    For all records inside of the store's aggregation tree ~attrName will resolve to the attribute of the store class found with record.getStore() method. If there are no such an attribute in the store, the next available store upper in aggregation tree will be used (as regular records stores can be nested), or the default store if there are no one.

    - - -

    Store is the subclass of the Record. It's defined extending the Store abstract base class. It behaves as a regular record in most aspects.

    -

    store._defaultStore

    -

    Reference to the master store used for lookups if the current store doesn't have the required attribute and there are no other store found upper in the ownership chain.

    -

    Defaults to the Store.global. May be explicitly defined to create custom store lookup chains across the ownership hierarchy.

    -

    static Store.global

    -

    The default singleton store class. Is always the last store to lookup when resolving ~reference.

    -

    Use the default store for the globally shared data only. Each application page must have its local store.

    -
    @define class MyStore extends Store {
    -    static attributes = {
    -        users : User.Collection,
    -        roles : Role.Collection
    -    }
    -}
    -
    -Store.global = new MyStore();
    -
    -// Now the reference '~users` will point to users collection from the MyStore.
    -
    -

    recordOrCollection.getStore()

    -

    Return the closest store. Used internally to resolve symbolic ~reference relative to the store.

    -

    Method looks for the Store subclass traversing the ownership chain of current aggregation tree upwards. If there are no store found this way, default Store from Store.global is returned.

    -

    recordOrCollection.clone({ pinStore : true })

    -

    Make the cloned object to preserve the reference to its original store.

    -

    Cloned objects don't have an owner by default, thus they loose the reference to their store as no ownership chain can be traversed. pinStore option should be used in such a cases.

    -

    Tools

    -

    Logging

    -

    Type-r doesn't attempt to manage logs. Instead, it treat logs as an event stream and uses the logger singleton as a log router.

    -

    By default, the logger has the default listener writing events to the console.

    -

    log( level, topic, msg, props? )

    -

    Method used to trigger the log event. Same as logger.trigger( level, topic, msg, props? ).

    -

    The level corresponds to the logging methods of the console object: error, warn, info, log, debug.

    -

    topic is the short string used to denote the log source source and functional area. Type-R topics are prefixed with TR, and looks like TR:TypeError. -If you want to use Type-R

    -
    import { log } from 'type-r'
    -
    -log( 'error', 'client-api:users', 'No user with the given id', { user } );
    -
    -

    logger.off()

    -
    import { logger } from 'type-r'
    -
    -// Remove all the listeners
    -logger.off();
    -
    -// Remove specific log level listeners (corresponds to the console methods, like console.log, console.warn, etc)
    -logger.off( 'warn' );
    -
    -

    logger.throwOn( level )

    -

    Sometimes (for instance, in a test suite) developer would like Type-R to throw exceptions on type errors instead of the console warnings.

    -
    import { logger } from 'type-r'
    -
    -logger.off().throwOn( 'error' ).throwOn( 'warn' );
    -
    -

    Or, there might be a need to throw exceptions on error in the specific situation (e.g. throw if the incoming HTTP request is not valid to respond with 500 HTTP code).

    -
    import { Logger } from 'type-r'
    -
    -async function processRequest( ... ){
    -    // Create an empty logger
    -    const logger = new Logger();
    -
    -    // Tell it to throw exceptions.
    -    logger.throwOn( 'error' ).throwOn( 'warn' );
    -
    -    // Override the default logger with option. Constructor will throw on error or warning.
    -    const request = new RequestBody( json, { parse : true, logger });
    -    ...
    -}
    -
    -

    logger.on( level, handler )

    -

    Type-R log message is the regular event. It's easy to attach custom listeners to integrate third-party log management libraries.

    -
    import { logger } from 'type-r'
    -
    -logger
    -    .off()
    -    .on( 'error', ( topic, msg, props ) => {
    -        // Log errors with bunyan
    -    } );
    -
    -

    Class Definitions

    -

    Type-R mechanic is based on class transformations at the moment of module load. These transformations are controlled by definitions in static class members.

    -

    decorator @definitions({ propName : rule, ... })

    -

    Treat specified static class members as definitions. When @define decorator is being called, definitions are extracted from static class members and mixins and passed as an argument to the Class.onDefine( definition ).

    -

    Class definitions are intended to use in the abstract base classes and they are inherited by subclasses. You don't need to add any new definitions to existing Type-R classes unless you want to extend the library, which you're welcome to do.

    -

    rule mixinRules.value

    -

    Merge rule used to mark class definitions. The same rule is also applied to all mixin members if other rule is not specified.

    -
    @define
    -@definitions({
    -    urlRoot : mixinRules.value
    -})
    -class X {
    -    static urlRoot = '/api';
    -
    -    static onDefine( definition ){
    -        this.prototype.urlRoot = definition.urlRoot;
    -    }
    -}
    -
    -

    rule mixinRules.protoValue

    -

    Same as mixinRules.value, but the value is being assigned to the class prototype.

    -
    @define
    -@definitions({
    -    urlRoot : mixinRules.protoValue
    -})
    -class X {
    -    static urlRoot = '/api';
    -}
    -
    -assert( X.prototype.urlRoot === '/api' );
    -
    -

    rule mixinRules.merge

    -

    Assume the property to be the key-value hash. Properties with the same name from mixins are merged.

    -
    const M = {
    -    attributes : {
    -        b : 1
    -    }
    -};
    -
    -@define
    -@mixins( M )
    -@definitions({
    -    attributes : mixinRules.merge
    -})
    -class X {
    -    static attributes = {
    -        a : 1
    -    };
    -
    -    onDefine( definitions ){
    -        const { attributes } = definitions;
    -        assert( attributes.a === attributes.b === 1 );
    -    }
    -}
    -
    -

    decorator @define

    -

    Extract class definitions, call class definition hooks, and apply mixin merge rules to inherited class members.

    -
      -
    1. Call static onExtend( BaseClass ) hook.
    2. -
    3. Extract definitions from static class members and all the mixins applied, and pass them to onDefine( definitions, BaseClass ) hook.
    4. -
    5. Apply merge rules for overriden class methods.
    6. -
    -

    All Type-R class definitions must be precedeed with the @define (or @predefine) decorator.

    -
    @define
    -@definitions({
    -    attributes : mixinRules.merge
    -})
    -class Record {
    -    static onDefine( definitions, BaseClass ){
    -        definitions.attributes && console.log( JSON.stringify( definitions.attributes ) );
    -    }
    -}
    -
    -// Will print "{ "a" : 1 }"
    -@define class A extends Record {
    -    static attributes = {
    -        a : 1
    -    }
    -}
    -
    -// Will print "{ "b" : 1 }"
    -@define class B extends Record {
    -    static attributes = {
    -        b : 1
    -    }
    -}
    -
    -

    decorator @define( mixin )

    -

    When called with an argument, @define decorator applies the given mixin as if it would be the first mixin applied. -In other aspects, it behaves the same as the @default decorator without argument.

    -

    static Class.onExtend( BaseClass )

    -

    Called from the @predefine or as the first action of the @define. Takes base class constructor as an argument.

    -

    static Class.onDefine( definition, BaseClass )

    -

    Called from the @define or Class.define() method. Takes class definition (see the @definitions decorator) as the first argument.

    -

    decorator @predefine

    -

    The sequence of @predefine with the following Class.define() call is equivalent to @define decorator. It should be used in the case if the class definition must reference itself, or multiple definitions contain circular dependency.

    -

    It calls static onExtend( BaseClass ) function if it's defined. It assumes that the Class.define( definitions ) method will be called later, and attaches Class.define method to the class if it was not defined.

    -

    static Class.define( definitions? )

    -

    Finalized the class definition started with @predefine decorator. Has the same effect as the @define decorator excepts it assumes that Class.onExtend() static function was called already.

    -

    Mixins

    -

    decorator @mixins( mixinA, mixinB, ... ) class X ...

    -

    Merge specified mixins to the class definition. Both plain JS object and class constructor may be used as mixin. In the case of the class constructor, missing static members will copied over as well.

    -
        import { mixins, Events } from 'type-r'
    -    ...
    -
    -    @define
    -    @mixins( Events, plainObject, MyClass, ... )
    -    class X {
    -        ...
    -    }
    -
    -

    static Class.mixins

    -

    Class member holding the state of the class mixins.

    - - -

    Merge rules

    -

    decorator @mixinRules({ propName : rule, ... })

    -

    The rule is the reducer function which is applied when there are several values for the particular class members are defined in different mixins or the class, or if the class member is overriden by the subclass.

    - - -

    rule mixinRules.classFirst

    -

    Assume the property to be the function. Call functions from mixins in sequence: f1.apply( this, arguments ); f2.apply( this, arguments );...

    -

    rule mixinRules.classLast

    -

    Same as sequence, but functions are called in the reverse sequence.

    -
    @define
    -@mixinRules({
    -    componentWillMount : mixinRules.classLast
    -})
    -class Component {
    -    componentWillMount(){
    -        console.log( 1 );
    -    }
    -}
    -
    -const M = {
    -    componentWillMount(){
    -        console.log( 2 );
    -    }
    -}
    -
    -@define
    -@mixins( M )
    -class X extends Component {
    -    componentWillMount(){
    -        console.log( 3 );
    -    }
    -}
    -
    -const x = new X();
    -x.componentWillMount();
    -// Will print 1, 2, 3
    -
    -
    -

    rule mixinRules.pipe

    -

    Assume the property to be the function with a signature ( x : T ) => T. Join functions from mixins in a pipe: f1( f2( f3( x ) ) ).

    -

    rule mixinRules.defaults

    -

    Assume the property to be the function returning object. Merge objects returned by functions from mixins, executing them in sequence.

    -

    rule mixinRules.every

    -

    Assume property to be the function returning boolean. Return true if all functions from mixins return truthy values.

    -

    rule mixinRules.some

    -

    Same as every, but return true when at least one function from mixins returns true.

    -

    Release Notes

    -

    3.0.0

    -

    Breaking changes

    -

    Changed semantic which needs to be refactored:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.x3.x
    Typeless attributevalue(x)type(null).value(x)
    Infer type from the valuex (except functions)value(x), or x (except functions)
    record.parse() overriderecord._parse(json)no such a method, remove it
    record attributes iterationrecord.forEachAttr(obj, iteratee)record.forEach(iteratee)
    Shared objectUser.sharedshared( User )
    one-to-many relationshipRecordClass.from( ref )memberOf( ref )
    many-to-many relationshipCollectionClass.from( ref )subsetOf( ref, CollectionClass? )
    construct from object/array-RecordOrCollectionClass.from( json, options? )
    -

    New attribute definition notation

    -

    Starting from version 3.X, Type-R does not modify built-in global JS objects. New type(T) attribute definition notation is introduced to replace T.has.

    -

    There's type-r/globals package for compatibility with version 2.x which must be imported once with import 'type-r/globals'. -If this package is not used, the code must be refactored according to the rules below.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.x3.x
    UNIX TimestampDate.timestampimport { Timestamp } from 'type-r/ext-types'
    Microsoft dateDate.microsoftimport { MicrosoftDate } from 'type-r/ext-types'
    IntegerInteger and Number.integerimport { Integer } from 'type-r/ext-types'
    Create metatype from constructorCtor.hastype(Ctor)
    Typed attribute with default valueCtor.value(default)type(Ctor).value(default)
    Attribute "Required" checkCtor.isRequiredtype(Ctor).required
    -

    First-class TypeScript support

    -
      -
    • Infer<typeof Metatype> infers TypeScript type from the Type-R attribute metatype.
    • -
    • InferAttrs<typeof attributes> infers TypeScript type for the Type-R attributes definitions.
    • -
    • attributes({ attrDefs }) returns the properly typed TypeScript Record class.
    • -
    -

    TypeScript attributes definitions:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.x3.x
    Extract Type-R type with Reflect.metadata@attr name : T@auto name : T
    Extract Type-R type & specify the default valuenot possible@auto(default) name : T
    Explicitly specify the type@attr(T) name : T@type(T).as name : T
    Infer Type-R type from default value@attr(default) name : T@value(default).as name : T
    Specify type and default value@attr(T.value(default)) name : T@type(T).value(default).as name : T
    -

    Other improvements

    -
      -
    • Collection class now proxies ES6 Array methods
    • -
    • New logger API which easy to override or turn off.
    • -
    • Improved error messages.
    • -
    • Type.from( json, options? ) method to restore object from JSON with a strict type check and validation.
    • -
    -
    @define class User extends Record {
    -    // There's an HTTP REST enpoint for users.
    -    static endpoint = restfulIO( '/api/users' );
    -
    -    @auto name : string
    -
    -    // Collection of Role records represented as an array of role.id in JSON.
    -    // When the "roles" attribute will be accessed for the first time,
    -    // User will look-up for a 'roles' attribute of the nearest store to resolve ids to actual Users.
    -    @subsetOf( '~roles' ).as roles : Collection<Role>
    -}
    -
    -@define class Role extends Record {
    -    static endpoint = restfulIO( '/api/roles' );
    -    @auto name : string
    -}
    -
    -// Store is the regular Record, nothing special.
    -@define class UsersDirectory extends Store {
    -    // When this record is fetched, fetch all the attributes instead.
    -    static endpoint = attributesIO();
    -
    -    // '~roles' references from all aggregated collections
    -    // will point to here, because this is the nearest store.
    -    @type( User.Collection ).as users : Collection<User>
    -    @type( Role.Collection ).as roles : Collection<Role>
    -}
    -
    -const directory = new UsersDirectory();
    -await directory.fetch();
    -
    -for( let user of directory.users ){
    -    assert( user.roles.first().users.first() instanceOf User );
    -}
    -
    -

    2.1.0

    -

    This release adds long-awaited HTTP REST endpoint.

    - -

    2.0.0

    -

    This release brings new features which fixes problems with component's inheritance in React bindings and implements long-awaited generic IO implementation based on ES6 promises.

    -

    There shouldn't be breaking changes unless you're using custom logger or React bindings (formerly known as React-MVx, with a name changed to React-R in new release).

    -

    Generic IO support

    -

    New IOEndpoint concept is introduced, making it easy to create IO abstractions. To enable Record and Collection IO API, you need to assign IO endpoint in the class definition.

    -

    Endpoint is the class defining CRUD and list operations on JSON data, as well as the methods to subscribe for the data changes. There are two endpoints included with 2.0 release, memoryIO which is suitable for mock testing and localStorageIO which could be used in demos and prototypes. They can be used as a references as starting points to define your own IO endpoints.

    -
    @define class User extends Record {
    -    static endpoint = memoryIO();
    -    static attributes = {
    -        name : String,
    -        ...
    -    }
    -}
    -
    -

    There are three Record IO methods (save(), fetch(), and destroy()) and two collection IO method (fetch() and liveUpdates()) ). All IO methods returns ES6 promises, so you either must have the runtime supporting ES6 or use the ES6 promise polyfill. The promises are modified to be abortable (all of them have abort() method).

    -
    const user = new User({ name : 'John' });
    -user.save().then( () => {
    -    console.log( `new user is added ${ user.id }` )
    -});
    -
    -

    There's the special attributesIO() endpoint to fetch all of attributes independently and return the combined promise. This is the recommended way of fetching the data required by SPA page.

    -
    @define class PageStore extends Store {
    -    static endpoint = attributesIO();
    -    static attributes = {
    -        users : User.Collection,
    -        roles : UserRole.Collection,
    -        ...
    -    }
    -}
    -
    -const store = new PageStore();
    -store.fetch().then( () =>{
    -    // render your page
    -});
    -
    -

    It's possible to define or override the defined endpoint for the nested model or collection using type().endpoint() type-R attribute annotation.

    -
    @define class PageStore extends Store {
    -    static endpoint = attributesIO();
    -    static attributes = {
    -        users : type( User.Collection ).endpoint( restful( '/api/users' ) ),
    -        roles : type( UserRole.Collection ).endpoint( restful( '/api/userroles' ) ),
    -        ...
    -    }
    -}
    -
    - - -

    New mixins engine

    -

    Type-R metaprogramming system built on powerful mixins composition with configurable member merge rules. In 2.0 release, mixins engine was rewritten to properly apply merge rules on inheritance. This feature is heavily used in Type-R React's bindings and is crucial to prevent errors when extending the React.Component subclasses.

    -

    An example illustrating the principle:

    -
    @define
    -// Define the class with 
    -@mixinRules({
    -    componentWillMount : mixinRules.classLast,
    -    componentWillUnmount : mixinRules.classFirst
    -})
    -class Component {
    -    componentWillMount(){
    -        console.log( 1 );
    -    }
    -
    -    componentWillUnmount(){
    -        console.log( 3 );
    -    }
    -}
    -
    -@define
    -@mixins({
    -    componentWillMount(){
    -        console.log( 2 );
    -    },
    -
    -    componentWillUnmount(){
    -        console.log( 2 );
    -    }
    -})
    -class MyBaseComponent extends Component {
    -    componentWillMount(){
    -        console.log( 3 );
    -    }
    -
    -    componentWillUnmount(){
    -        console.log( 1 );
    -    }
    -}
    -
    -

    In this example, all of the methods defined in the mixin, base class, and subclass will be called in the order specified in the console.log.

    -

    Other changes

    -
      -
    • Update pipeline was rewritten to improve record's initialization speed (collection's fetch speed is improved by 30%).
    • -
    • Fixed bug causing dynamic type checks to be disabled in records constructors.
    • -
    • New implementation of the Collection.subsetOf which both fixes some edge case bugs and is more efficient.
    • -
    • New logger handling NODE_ENV variable setting.
    • -
    -
    -
    - - diff --git a/docs/index.md b/docs/index.md index cc8b7d55..8da75d81 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,248 +1,30 @@ --- -title: Type-R 3.0 API Reference +title: Type-R v4.0 API Reference language_tabs: - javascript - - typescript -logoTitle: Type-R 3.0 +logoTitle: Type-R v4.0 toc_footers: - - GitHub repository - - Report the bug + - GitHub repository + - Report the bug - Ask the question - - Supported by includes: - - record - - collection - - observable - - validation - - io - - tools - - releasenotes + - README + - models/README + - models/src/README + - ext-types/README + - models/src/model/README + - models/src/collection/README + - endpoints/README + - models/src/relations/README + - react/README + - examples/README + - mixture/README + - ReleaseNotes search: true --- -# Getting started - -## Overview - -Type-R is the TypeScript and JavaScript model framework helping to define and manage the complex application state as a combination of reusable parts. Type-R cover the needs of business logic and data layers in 3-tier application architecture, providing the presentation layer with the unified technique to handle the UI and domain state. Type-R data structures look and feel (and, in some aspects, behaves) more like classes in the statically typed languages. - -Type-R in unopinionated on the way how an application state should be managed ("single source of truth" or "distributed state"). It can support all approaches equally well being not dependent on singletons and having powerful capabilities for state synchronization. - -![overview](images/3-layer-client.png) - -A state is defined as a superposition of typed records and collections. A record is a class with a known set of attributes of predefined types possibly holding other records and collections in its attributes, describing the data structure of arbitrary complexity. Record with its attributes forms an aggregation tree with deeply observable attributes changes. Attribute types are checked on assignments and invalid changes are being rejected, therefore it is guaranteed that the application state will preserve the valid shape. - -Application state defined with Type-R is serializable to JSON by default. Aggregation tree of records and collections is mapped in JSON as a tree of plain objects and arrays. Normalized data represented as a set of collections of records cross-referencing each other are supported as first-class serialization scenario. - -A record may have an associated IOEndpont representing the I/O protocol for CRUD and collection fetch operations which enables the persistence API for the particular record/collection class pair. Some useful endpoints (`restfulIO`, `localStorageIO`, etc) are provided by `type-r/endpoints/*` packages, and developers can define their own I/O endpoints implementing any particular persistence transport or API. - -Record attributes may have custom validation rules attached to them. Validation is being triggered transparently on demand and its result is cached across the record/collection aggregation tree, making subsequent calls to the validation API extremely cheap. - -All aspects of record behavior including serialization and validation can be controlled on attribute level with declarative definitions combining attribute types with metadata. Attribute definitions ("metatypes") can be reused across different models forming the domain-specific language of model declarations. Some useful attribute metatypes (`Email`, `Url`, `MicrosoftDate`, etc) are provided by `type-r/ext-types` package. - -## How Type-R compares to X? - -Type-R (former "NestedTypes") project was started in 2014 in Volicon as a modern successor to BackboneJS models, which would match Ember Data in its capabilities to work with a complex state while retaining the BackboneJS simplicity, modularity, and some degree of backward API compatibility. It replaced BackboneJS in the model layer of Volicon products, and it became the key technology in Volicon's strategy to gradually move from BackboneJS Views to React in the view layer. - -[Ember Data](https://guides.emberjs.com/v2.2.0/models/) is the closest thing to Type-R by its capabilities, with [BackboneJS models and collections](http://backbonejs.org/#Model) being the closest thing by the API, and [mobx](https://github.com/mobxjs/mobx) being pretty close in the way how the UI state is managed. - -Type-R, however, takes a very different approach to all of them: - -- Type-R models look and feel more like classes in a statically typed language with the majority of features being controlled by attribute metadata. -- Type-R is built around the concept of _aggregation trees_ formed by nested records and collections and it knows how to clone, serialize, and validate complex objects with cross-references properly. -- In contrast to BackboneJS, Record is _not an object hash_ but the class with statically typed and dynamically checked attributes. -- In contrast to mobx, Type-R detects _deeply nested changes_. -- In contrast to Ember Data, Type-R doesn't require the singleton global store. In Type-R, stores are a special kind of records and there might be as many dynamically created and disposed of stores as you need, starting with no stores at all. - -Feature | Type-R | Backbone Models | Ember Data | mobx --|-|-|-|- -Observable changes in object graph | ✓ | - | - | ✓ -JSON Serialization | ✓ | ✓ | ✓ | - -Validation | ✓ | ✓ | ✓ | - -Dynamic Type Safety | ✓ | - | for serialization only | - -Aggregation | ✓ | - | - | - -Relations by id | ✓ | - | ✓ | - -Generalized I/O | ✓ | sync function | ✓ | - - -## Features by example - -Here's the brief overview of features groped by application purpose. - -### Persistent domain state - -The basic building block is the `Record` class. To fetch data from the server, a developer creates the subclass of the `Record` describing its attribute types and attaches the `restfulIO` endpoint. It enables the persistence API allowing the developer to fetch the collection from the server. `restfulIO` expects the server to implement the standard RESTful API expected by BackboneJS models. - -- `GET /api/users` - fetch all the users -- `POST /api/users` - create the user -- `GET /api/users/:id` - fetch the user with a given id -- `PUT /api/users/:id` - update the user with a given id -- `DELETE /api/users/:id` - delete the user with a given id - -Record and collection are serializable to and can be parsed from JSON with no additional effort. A mapping to JSON can be customized for collections, records, and individual attributes. The Record validates all updates casting attribute values to declared attribute types to protect the state structure from the protocol incompatibilities and improper assignments. - -```javascript -@define User extends Record { - static endpoint = restfulIO( '/api/users' ); - static attributes = { - name : String, - email : String, - createdAt : Date - } -} - -const users = new User.Collection(); -await users.fetch(); - -expect( users.first().createdAt ).toBeInstanceOf( Date ); -expect( typeof users.toJSON()[ 0 ].createdAt ).toBe( "string" ); -``` - -```typescript -@define User extends Record { - static endpoint = restfulIO( '/api/users' ); - - // Type-R can infer attribute types from TypeScript type annotations. - @auto name : string - @auto email : string - @auto createdAt : Date -} - -const users : Collection = new User.Collection(); -await users.fetch(); - -expect( users.first().createdAt ).toBeInstanceOf( Date ); -expect( typeof users.toJSON()[ 0 ].createdAt ).toBe( "string" ); -``` - -### UI state and observable changes - -Type-R provides the universal technique to working with the UI and domain state. To define the UI state, a developer creates the subclass of the `Record` with attributes holding all the necessary state data possibly along with the persistent data which can become the part of the same local UI state. The UI state itself can be a part of some particular view or UI component, it can be managed as a singleton ("single source of truth"), or both at the same time. Type-R is unopinionated on the application state structure leaving this decision to the developer. - -Records and collections form an aggregation tree with deeply observable changes, so it's enough to subscribe to the single `change` event from the `UIState` to get updates on both data arrival and local changes of the state attributes. Records and collections can be indefinitely nested to describe a state of arbitrary complexity. The developer can attach reactions on changes to the records, their individual attributes, and collections. Additional changes made in reactions will be executed in the scope of the same "change transaction" and won't trigger additional change events. - - -```javascript -@define UIState extends Record { - static attributes = { - users : User.Collection, - selectedUser : memberOf( 'users' ) - } -} - -const uiState = new UIState(); - -uiState.on( 'change', () => { - console.log( 'Something is changed' ); - updateUI(); -}); - -uiState.users.fetch(); -``` - -```typescript -@define UIState extends Record { - // For collections and more complex types attribute type must be provided explicitly - @type( User.Collection ).as users : Collection - - @memberOf( 'users' ).as selectedUser : User -} - -const uiState = new UIState(); - -uiState.on( 'change', () => { - console.log( 'Something is changed' ); - updateUI(); -}); - -uiState.users.fetch(); -``` - -### Validation - -Type-R supports validation as attribute-level checks attached to attribute definitions as metadata. Attribute type together with checks forms an "attribute metatype", which can be defined separately and reused across multiple record definitions. - -Validation rules are evaluated recursively on the aggregation tree on first access to the validation API, and validations results are cached in records and collections across the tree till the next update. The validation is automatic, subsequent calls to the validation API are cheap, and the developer doesn't need to manually trigger the validation on data changes. - -The majority of checks in a real application will be a part of attribute "metatypes", while the custom validation can be also defined on the `Record` and `Collection` level to check data integrity and cross-attributes dependencies. - -```javascript -const Email = type( String ) - .check( x => !x || x.indexOf( '@' ) >= 0, "Doesn't look like an email" ); - -@define User extends Record { - static endpoint = restfulIO( '/api/users' ); - static attributes = { - name : type( String ).required, - email : type( Email ).required, - createdAt : type( Date ).check( x => x.getTime() <= Date.now() ) - } -} - -const users = new User.Collection(); -users.add({ email : 'john' }); -expect( users.isValid() ).toBe( false ); -expect( users.first().isValid() ).toBe( false ); - -users.first().name = "John"; -users.first().email = "john@ny.com"; -expect( users.isValid() ).toBe( true ); -``` - -```typescript -const Email = type( String ) - .check( x => !x || x.indexOf( '@' ) >= 0, "Doesn't look like an email" ); - -@define User extends Record { - static endpoint = restfulIO( '/api/users' ); - - // @type(...).as converts Type-R attribute type definition to the TypeScript decorator. - @type( String ).required.as - name : string - - @type( Email ).required.as - email : string - - @type( Date ).check( x => x.getTime() <= Date.now() ).as - createdAt : Date -} - -const users = new User.Collection(); -users.add({ email : 'john' }); -expect( users.isValid() ).toBe( false ); -expect( users.first().isValid() ).toBe( false ); - -users.first().name = "John"; -users.first().email = "john@ny.com"; -expect( users.isValid() ).toBe( true ); -``` - -## Installation and requirements - -Is packed as UMD and ES6 module. No peer dependencies are required. - -`npm install type-r --save-dev` - - - - - -## ReactJS bindings - -[React-MVx](https://volicon.github.io/React-MVx/) is a glue framework which uses Type-R to manage the UI state in React and the [NestedLink](https://github.com/Volicon/NestedLink) library to implement two-way data binding. React-MVx provides the complete MVVM solution on top of ReactJS, featuring: - -- Type-R [Record](https://volicon.github.io/Type-R/#record) to manage the local [component's state](https://volicon.github.io/React-MVx/#state). -- [two-way data binding](https://volicon.github.io/React-MVx/#link) for UI and domain state. -- Hassle-free form validation (due to the combination of features of Type-R and NestedLink). -- [Type-R type annotation](https://volicon.github.io/Type-R/#definition) used to define component [props](https://volicon.github.io/React-MVx/#props) and [context](https://volicon.github.io/React-MVx/#context). - -## Usage with NodeJS - -Type-R can be used at the server side to build the business logic layer by defining the custom I/O endpoints to store data in a database. Type-R dynamic type safety features are particularly advantageous when schema-less JSON databases (like Couchbase) are being used. - -![server](images/3-layer-server.png) - diff --git a/docs/lib/layouts/layout.html b/docs/lib/layouts/layout.html index 46096e3a..e01ed1d3 100644 --- a/docs/lib/layouts/layout.html +++ b/docs/lib/layouts/layout.html @@ -6,10 +6,10 @@ {{title}} - - - - + + + + - + + + diff --git a/examples/checklistTree/package.json b/examples/checklistTree/package.json new file mode 100644 index 00000000..d09399ee --- /dev/null +++ b/examples/checklistTree/package.json @@ -0,0 +1,31 @@ +{ + "private": true, + "name": "checklist-tree", + "version": "2.0.0", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@type-r/models": "^4.0.0", + "@type-r/react": "^4.0.0", + "react": "^16.1.1", + "react-dom": "^16.1.1" + }, + "devDependencies": { + "@babel/core": "*", + "@babel/plugin-proposal-class-properties": "^7.5.5", + "@babel/plugin-proposal-decorators": "^7.4.4", + "@babel/plugin-transform-runtime": "^7.5.5", + "@babel/preset-env": "^7.5.5", + "@babel/preset-react": "^7.0.0", + "babel-loader": "*", + "css-loader": "*", + "source-map-loader": "*", + "style-loader": "*", + "webpack": "^4.38.0", + "webpack-cli": "^3.3.6" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "node_modules/.bin/webpack", + "watch": "node_modules/.bin/webpack --progress --colors --watch" + } +} diff --git a/examples/checklistTree/screenshot.png b/examples/checklistTree/screenshot.png new file mode 100644 index 00000000..c43a1923 Binary files /dev/null and b/examples/checklistTree/screenshot.png differ diff --git a/examples/checklistTree/src/index.jsx b/examples/checklistTree/src/index.jsx new file mode 100644 index 00000000..3045aee2 --- /dev/null +++ b/examples/checklistTree/src/index.jsx @@ -0,0 +1,85 @@ +import './styles.css' +import React from 'react' +import ReactDOM from 'react-dom' + +import { define, Model, Collection } from '@type-r/models' +import { localStorageIO } from '@type-r/endpoints' +import { useModel, useIO, pureRenderProps } from '@type-r/react' + +// Import checklist model definition. "Model" is a class with serializable and observable attributes. +import { ChecklistItem } from './model' + +// Local counter to help us count top-level renders. +let _renders = 0; + +// Type-R model for the App state. +@define class AppState extends Model { + // The state is persisted in localStorage + static endpoint = localStorageIO( "/@type-r/react/examples" ); + + static attributes = { + id : "checklistTree", // Persistent model needs to have an id + items : Collection.of( ChecklistItem ) + } +} + +const App = () => { + // Create the AppState model as a part of the local component state. + // If anything will change inside (no matter how deep), the component will notice it and update itself. + const state = useModel( AppState ); + + // Save and restore state. Executed once after mount. + const isReady = useIO( async () => { + window.onunload = () => state.save(); + + await state.fetch(); + }); + + return isReady ? +
    +
    Renders count: { ++_renders } + +
    + +
    + : "Loading..." +} + +const List = + // Render the component again only when the listed props changed. + pureRenderProps({ + // it has to know the type of each prop. The "type" is a JS constructor or Type-R attribute type annotation. + items : Collection.of( ChecklistItem ) + }, + ({ items }) => +
    + { items.map( item => ( + /* models have globally unique cid - client-side id to be used as 'key' */ + + ))} +
    +); + +const Item = ({ model }) => +
    +
    + + + { model.created.toLocaleTimeString() } + + + + +
    + +
    ; + +// That's really it! Let's render it. +ReactDOM.render( , document.getElementById( 'app-mount-root' ) ); diff --git a/examples/checklistTree/src/model.js b/examples/checklistTree/src/model.js new file mode 100644 index 00000000..048e1a74 --- /dev/null +++ b/examples/checklistTree/src/model.js @@ -0,0 +1,33 @@ +// Data objects are defined in nestedtypes package. +import { Model, Collection, define, type } from '@type-r/models' + +@define class Checklist extends Collection { + get checked(){ return this.every( item => item.checked ); } + set checked( checked ){ + if( checked !== this.checked ){ + this.updateEach( item => { item.checked = checked } ); + } + } +} + +@define +export class ChecklistItem extends Model { + static Collection = Checklist; + + static attributes = { // <- Here's an attribute spec. Think of it as a type spec. + name : String, + created : Date, + checked : type( Boolean ).watcher( 'onCheckedChange' ), + subitems : type( Checklist ).watcher( 'onSubitemsChange' ) + }; + + onCheckedChange( checked ){ this.subitems.checked = checked; } + + onSubitemsChange( subitems ){ + if( subitems.length ){ + this.checked = this.subitems.checked; + } + } + + remove(){ this.collection.remove( this ); } +} \ No newline at end of file diff --git a/examples/checklistTree/src/styles.css b/examples/checklistTree/src/styles.css new file mode 100644 index 00000000..c177998a --- /dev/null +++ b/examples/checklistTree/src/styles.css @@ -0,0 +1,40 @@ +.checkbox { + display: inline-block; + width: 10px; + height: 10px; + border: solid; + border-width: 1px; + margin: 3px; + vertical-align: middle; +} + +.children { + margin-left: 1em; +} + +.checkbox.selected { + background-color: black; +} + +input { + border: none; + border-bottom: solid; + border-width: 1px; + margin: 3px; + margin-left : 10px; +} + +input:focus { + outline: none; + border-width: 2px; +} + +button { + border-radius: 3px; + background-color: white; +} + +.created { + margin : 3px; + font-size: 11px; +} \ No newline at end of file diff --git a/examples/checklistTree/webpack.config.js b/examples/checklistTree/webpack.config.js new file mode 100644 index 00000000..30254704 --- /dev/null +++ b/examples/checklistTree/webpack.config.js @@ -0,0 +1,54 @@ +var webpack = require( 'webpack' ), + path = require( 'path' ); + +var config = { + entry : { + app : './src/index.jsx' + }, + + output : { + // export itself to a global var + path : __dirname + '/dist', + publicPath : '/dist/', + filename : '[name].js' + }, + + mode : process.env.NODE_ENV || 'development', + + devtool : 'source-map', + + resolve : { + modules : [ 'node_modules', 'src' ], + // alias : { //use `npm run deploy:examples` in main project + // 'react-mvx' : path.resolve(__dirname, '../..' ) + // } + }, + + module : { + rules : [ + { + test : /\.css$/, + use : [ + { + loader: "style-loader" + }, + { + loader: "css-loader" + } + ] + }, + { + test : /\.jsx?$/, + exclude : /(node_modules|lib)/, + loader : 'babel-loader' + }, + { + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + } + ] + } +}; + +module.exports = config; \ No newline at end of file diff --git a/examples/js-starter/.babelrc b/examples/js-starter/.babelrc new file mode 100644 index 00000000..335abe77 --- /dev/null +++ b/examples/js-starter/.babelrc @@ -0,0 +1,15 @@ +{ + "presets":[ + "@babel/preset-react", + [ + "@babel/preset-env", + { + "targets": "> 0.25%, not dead" + } + ] + ], + "plugins": [ + ["@babel/plugin-proposal-decorators", { "legacy": true }], + ["@babel/plugin-proposal-class-properties", { "loose" : true }] + ] +} \ No newline at end of file diff --git a/examples/js-starter/dist/app.js b/examples/js-starter/dist/app.js new file mode 100644 index 00000000..f67c6f0d --- /dev/null +++ b/examples/js-starter/dist/app.js @@ -0,0 +1,31456 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "/dist/"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = "./src/index.jsx"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "../../mixture/lib/events.js": +/*!************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/events.js ***! + \************************************************************/ +/*! exports provided: EventMap, Messenger, Events */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Messenger", function() { return Messenger; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Events", function() { return Events; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _eventsource__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./eventsource */ "../../mixture/lib/eventsource.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EventMap", function() { return _eventsource__WEBPACK_IMPORTED_MODULE_1__["EventMap"]; }); + +/* harmony import */ var _mixins__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mixins */ "../../mixture/lib/mixins.js"); +/* harmony import */ var _tools__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./tools */ "../../mixture/lib/tools.js"); + + + + + +var strings = _eventsource__WEBPACK_IMPORTED_MODULE_1__["strings"], on = _eventsource__WEBPACK_IMPORTED_MODULE_1__["on"], off = _eventsource__WEBPACK_IMPORTED_MODULE_1__["off"], once = _eventsource__WEBPACK_IMPORTED_MODULE_1__["once"], trigger5 = _eventsource__WEBPACK_IMPORTED_MODULE_1__["trigger5"], trigger2 = _eventsource__WEBPACK_IMPORTED_MODULE_1__["trigger2"], trigger3 = _eventsource__WEBPACK_IMPORTED_MODULE_1__["trigger3"]; +var _idCount = 0; +function uniqueId() { + return 'l' + _idCount++; +} + +var Messenger = (function () { + function Messenger() { + this._events = void 0; + this._listeningTo = void 0; + this.cid = uniqueId(); + this.initialize.apply(this, arguments); + } + Messenger.onDefine = function (_a, BaseClass) { + var localEvents = _a.localEvents, _localEvents = _a._localEvents, properties = _a.properties; + if (localEvents || _localEvents) { + var eventsMap = new _eventsource__WEBPACK_IMPORTED_MODULE_1__["EventMap"](this.prototype._localEvents); + localEvents && eventsMap.addEventsMap(localEvents); + _localEvents && eventsMap.merge(_localEvents); + this.prototype._localEvents = eventsMap; + } + if (properties) { + Object.defineProperties(this.prototype, Object(_tools__WEBPACK_IMPORTED_MODULE_3__["transform"])({}, properties, toPropertyDescriptor)); + } + }; + Messenger.prototype.initialize = function () { }; + Messenger.prototype.on = function (events, callback, context) { + if (typeof events === 'string') + strings(on, this, events, callback, context); + else + for (var name_1 in events) + strings(on, this, name_1, events[name_1], context || callback); + return this; + }; + Messenger.prototype.once = function (events, callback, context) { + if (typeof events === 'string') + strings(once, this, events, callback, context); + else + for (var name_2 in events) + strings(once, this, name_2, events[name_2], context || callback); + return this; + }; + Messenger.prototype.off = function (events, callback, context) { + if (!events) + off(this, void 0, callback, context); + else if (typeof events === 'string') + strings(off, this, events, callback, context); + else + for (var name_3 in events) + strings(off, this, name_3, events[name_3], context || callback); + return this; + }; + Messenger.prototype.trigger = function (name, a, b, c, d, e) { + if (d !== void 0 || e !== void 0) + trigger5(this, name, a, b, c, d, e); + else if (c !== void 0) + trigger3(this, name, a, b, c); + else + trigger2(this, name, a, b); + return this; + }; + Messenger.prototype.listenTo = function (source, a, b) { + if (source) { + addReference(this, source); + source.on(a, !b && typeof a === 'object' ? this : b, this); + } + return this; + }; + Messenger.prototype.listenToOnce = function (source, a, b) { + if (source) { + addReference(this, source); + source.once(a, !b && typeof a === 'object' ? this : b, this); + } + return this; + }; + Messenger.prototype.stopListening = function (a_source, a, b) { + var _listeningTo = this._listeningTo; + if (_listeningTo) { + var removeAll = !(a || b), second = !b && typeof a === 'object' ? this : b; + if (a_source) { + var source = _listeningTo[a_source.cid]; + if (source) { + if (removeAll) + delete _listeningTo[a_source.cid]; + source.off(a, second, this); + } + } + else if (a_source == null) { + for (var cid in _listeningTo) + _listeningTo[cid].off(a, second, this); + if (removeAll) + (this._listeningTo = void 0); + } + } + return this; + }; + Messenger.prototype.dispose = function () { + if (this._disposed) + return; + this.stopListening(); + this.off(); + this._disposed = true; + }; + Messenger = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _mixins__WEBPACK_IMPORTED_MODULE_2__["define"], + Object(_mixins__WEBPACK_IMPORTED_MODULE_2__["definitions"])({ + properties: _mixins__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].merge, + localEvents: _mixins__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].merge + }) + ], Messenger); + return Messenger; +}()); + +var Events = Object(_tools__WEBPACK_IMPORTED_MODULE_3__["omit"])(Messenger.prototype, 'constructor', 'initialize'); +function toPropertyDescriptor(x) { + if (x) { + return typeof x === 'function' ? { get: x, configurable: true } : x; + } +} +function addReference(listener, source) { + var listeningTo = listener._listeningTo || (listener._listeningTo = Object.create(null)), cid = source.cid || (source.cid = uniqueId()); + listeningTo[cid] = source; +} + + +/***/ }), + +/***/ "../../mixture/lib/eventsource.js": +/*!*****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/eventsource.js ***! + \*****************************************************************/ +/*! exports provided: EventMap, EventDescriptor, EventHandler, on, once, off, strings, trigger2, trigger3, trigger5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventMap", function() { return EventMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventDescriptor", function() { return EventDescriptor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EventHandler", function() { return EventHandler; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "on", function() { return on; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "once", function() { return once; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "off", function() { return off; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "strings", function() { return strings; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "trigger2", function() { return trigger2; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "trigger3", function() { return trigger3; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "trigger5", function() { return trigger5; }); +/* harmony import */ var _tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./tools */ "../../mixture/lib/tools.js"); + +var EventMap = (function () { + function EventMap(map) { + this.handlers = []; + if (map) { + if (map instanceof EventMap) { + this.handlers = map.handlers.slice(); + } + else { + map && this.addEventsMap(map); + } + } + } + EventMap.prototype.merge = function (map) { + this.handlers = this.handlers.concat(map.handlers); + }; + EventMap.prototype.addEventsMap = function (map) { + for (var names in map) { + this.addEvent(names, map[names]); + } + }; + EventMap.prototype.bubbleEvents = function (names) { + for (var _i = 0, _a = names.split(eventSplitter); _i < _a.length; _i++) { + var name_1 = _a[_i]; + this.addEvent(name_1, getBubblingHandler(name_1)); + } + }; + EventMap.prototype.addEvent = function (names, callback) { + var handlers = this.handlers; + for (var _i = 0, _a = names.split(eventSplitter); _i < _a.length; _i++) { + var name_2 = _a[_i]; + handlers.push(new EventDescriptor(name_2, callback)); + } + }; + EventMap.prototype.subscribe = function (target, source) { + for (var _i = 0, _a = this.handlers; _i < _a.length; _i++) { + var event_1 = _a[_i]; + on(source, event_1.name, event_1.callback, target); + } + }; + EventMap.prototype.unsubscribe = function (target, source) { + for (var _i = 0, _a = this.handlers; _i < _a.length; _i++) { + var event_2 = _a[_i]; + off(source, event_2.name, event_2.callback, target); + } + }; + return EventMap; +}()); + +var EventDescriptor = (function () { + function EventDescriptor(name, callback) { + this.name = name; + if (callback === true) { + this.callback = getBubblingHandler(name); + } + else if (typeof callback === 'string') { + this.callback = + function localCallback() { + var handler = this[callback]; + handler && handler.apply(this, arguments); + }; + } + else { + this.callback = callback; + } + } + return EventDescriptor; +}()); + +var _bubblingHandlers = {}; +function getBubblingHandler(event) { + return _bubblingHandlers[event] || (_bubblingHandlers[event] = function (a, b, c, d, e) { + if (d !== void 0 || e !== void 0) + trigger5(this, event, a, b, c, d, e); + if (c !== void 0) + trigger3(this, event, a, b, c); + else + trigger2(this, event, a, b); + }); +} +var EventHandler = (function () { + function EventHandler(callback, context, next) { + if (next === void 0) { next = null; } + this.callback = callback; + this.context = context; + this.next = next; + } + return EventHandler; +}()); + +function listOff(_events, name, callback, context) { + var head = _events[name]; + var filteredHead, prev; + for (var ev = head; ev; ev = ev.next) { + if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || + (context && context !== ev.context)) { + prev = ev; + filteredHead || (filteredHead = ev); + } + else { + if (prev) + prev.next = ev.next; + } + } + if (head !== filteredHead) + _events[name] = filteredHead; +} +function listSend2(head, a, b) { + for (var ev = head; ev; ev = ev.next) + ev.callback.call(ev.context, a, b); +} +function listSend3(head, a, b, c) { + for (var ev = head; ev; ev = ev.next) + ev.callback.call(ev.context, a, b, c); +} +function listSend4(head, a, b, c, d) { + for (var ev = head; ev; ev = ev.next) + ev.callback.call(ev.context, a, b, c, d); +} +function listSend5(head, a, b, c, d, e) { + for (var ev = head; ev; ev = ev.next) + ev.callback.call(ev.context, a, b, c, d, e); +} +function listSend6(head, a, b, c, d, e, f) { + for (var ev = head; ev; ev = ev.next) + ev.callback.call(ev.context, a, b, c, d, e, f); +} +function on(source, name, callback, context) { + if (callback) { + var _events = source._events || (source._events = Object.create(null)); + _events[name] = new EventHandler(callback, context, _events[name]); + } +} +function once(source, name, callback, context) { + if (callback) { + var once_1 = Object(_tools__WEBPACK_IMPORTED_MODULE_0__["once"])(function () { + off(source, name, once_1); + callback.apply(this, arguments); + }); + once_1._callback = callback; + on(source, name, once_1, context); + } +} +function off(source, name, callback, context) { + var _events = source._events; + if (_events) { + if (callback || context) { + if (name) { + listOff(_events, name, callback, context); + } + else { + for (var name_3 in _events) { + listOff(_events, name_3, callback, context); + } + } + } + else if (name) { + _events[name] = void 0; + } + else { + source._events = void 0; + } + } +} +var eventSplitter = /\s+/; +function strings(api, source, events, callback, context) { + if (eventSplitter.test(events)) { + var names = events.split(eventSplitter); + for (var _i = 0, names_1 = names; _i < names_1.length; _i++) { + var name_4 = names_1[_i]; + api(source, name_4, callback, context); + } + } + else + api(source, events, callback, context); +} +function trigger2(self, name, a, b) { + var _events = self._events; + if (_events) { + var queue = _events[name], all = _events.all; + listSend2(queue, a, b); + listSend3(all, name, a, b); + } +} +; +function trigger3(self, name, a, b, c) { + var _events = self._events; + if (_events) { + var queue = _events[name], all = _events.all; + listSend3(queue, a, b, c); + listSend4(all, name, a, b, c); + } +} +; +function trigger5(self, name, a, b, c, d, e) { + var _events = self._events; + if (_events) { + var queue = _events[name], all = _events.all; + listSend5(queue, a, b, c, d, e); + listSend6(all, name, a, b, c, d, e); + } +} +; + + +/***/ }), + +/***/ "../../mixture/lib/index.js": +/*!***********************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/index.js ***! + \***********************************************************/ +/*! exports provided: tools, eventsApi, EventMap, Messenger, Events, isProduction, logEvents, Logger, logger, throwingLogger, log, Mixable, predefine, define, definitions, propertyListDecorator, definitionDecorator, MixinsState, mixins, mixinRules */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _eventsource__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./eventsource */ "../../mixture/lib/eventsource.js"); +/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "eventsApi", function() { return _eventsource__WEBPACK_IMPORTED_MODULE_0__; }); +/* harmony import */ var _tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tools */ "../../mixture/lib/tools.js"); +/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "tools", function() { return _tools__WEBPACK_IMPORTED_MODULE_1__; }); +/* harmony import */ var _events__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./events */ "../../mixture/lib/events.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EventMap", function() { return _events__WEBPACK_IMPORTED_MODULE_2__["EventMap"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Messenger", function() { return _events__WEBPACK_IMPORTED_MODULE_2__["Messenger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Events", function() { return _events__WEBPACK_IMPORTED_MODULE_2__["Events"]; }); + +/* harmony import */ var _logging__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./logging */ "../../mixture/lib/logging.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isProduction", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["isProduction"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "logEvents", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["logEvents"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Logger", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["Logger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "logger", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["logger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwingLogger", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["throwingLogger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "log", function() { return _logging__WEBPACK_IMPORTED_MODULE_3__["log"]; }); + +/* harmony import */ var _mixins__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mixins */ "../../mixture/lib/mixins.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Mixable", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["Mixable"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "predefine", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["predefine"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "define", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["define"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "definitions", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["definitions"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "propertyListDecorator", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["propertyListDecorator"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "definitionDecorator", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["definitionDecorator"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MixinsState", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["MixinsState"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mixins", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["mixins"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mixinRules", function() { return _mixins__WEBPACK_IMPORTED_MODULE_4__["mixinRules"]; }); + + + + + + + + + + +/***/ }), + +/***/ "../../mixture/lib/logging.js": +/*!*************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/logging.js ***! + \*************************************************************/ +/*! exports provided: isProduction, logEvents, Logger, logger, throwingLogger, log */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* WEBPACK VAR INJECTION */(function(process) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isProduction", function() { return isProduction; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "logEvents", function() { return logEvents; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Logger", function() { return Logger; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "logger", function() { return logger; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throwingLogger", function() { return throwingLogger; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "log", function() { return log; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _events__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./events */ "../../mixture/lib/events.js"); +/* harmony import */ var _mixins__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mixins */ "../../mixture/lib/mixins.js"); + + + +var isProduction = typeof process !== 'undefined' && process.env && "development" === 'production', logEvents = isProduction ? + ['error', 'info'] : + ['error', 'warn', 'debug', 'info', 'log']; +var Logger = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](Logger, _super); + function Logger() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.counter = {}; + return _this; + } + Logger.prototype.logToConsole = function (level, filter) { + return this.on(level, function (topic, msg, props) { + if (!filter || filter.test(topic)) { + var args = ["[" + topic + "] " + msg]; + for (var name_1 in props) { + args.push("\n\t" + name_1 + ":", toString(props[name_1])); + } + console[level].apply(console, args); + } + }); + }; + Logger.prototype.throwOn = function (level, filter) { + return this.on(level, function (topic, msg, props) { + if (!filter || filter.test(topic)) { + throw new Error("[" + topic + "] " + msg); + } + }); + }; + Logger.prototype.count = function (level, filter) { + var _this = this; + return this.on(level, function (topic, msg, props) { + if (!filter || filter.test(topic)) { + _this.counter[level] = (_this.counter[level] || 0) + 1; + } + }); + }; + Logger.prototype.on = function (a, b) { + return _super.prototype.on.call(this, a, b); + }; + Logger = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _mixins__WEBPACK_IMPORTED_MODULE_2__["define"] + ], Logger); + return Logger; +}(_events__WEBPACK_IMPORTED_MODULE_1__["Messenger"])); + +var toString = typeof window === 'undefined' ? + function (something) { + if (something && typeof something === 'object') { + var value = something.__inner_state__ || something, isArray = Array.isArray(value); + var body = isArray ? "[ length = " + value.length + " ]" : "{ " + Object.keys(value).join(', ') + " }"; + return something.constructor.name + ' ' + body; + } + return JSON.stringify(something); + } + : function (x) { return x; }; +var logger = new Logger(); +if (typeof console !== 'undefined') { + for (var _i = 0, logEvents_1 = logEvents; _i < logEvents_1.length; _i++) { + var event_1 = logEvents_1[_i]; + logger.logToConsole(event_1); + } +} +var throwingLogger = new Logger(); +throwingLogger.throwOn('error').throwOn('warn'); +var log = logger.trigger.bind(logger); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../node_modules/process/browser.js */ "../../node_modules/process/browser.js"))) + +/***/ }), + +/***/ "../../mixture/lib/mixins.js": +/*!************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/mixins.js ***! + \************************************************************/ +/*! exports provided: Mixable, predefine, define, definitions, propertyListDecorator, definitionDecorator, MixinsState, mixins, mixinRules */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mixable", function() { return Mixable; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "predefine", function() { return predefine; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "define", function() { return define; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "definitions", function() { return definitions; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "propertyListDecorator", function() { return propertyListDecorator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "definitionDecorator", function() { return definitionDecorator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MixinsState", function() { return MixinsState; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mixins", function() { return mixins; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mixinRules", function() { return mixinRules; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tools */ "../../mixture/lib/tools.js"); + + + +var Mixable = (function () { + function Mixable() { + } + Mixable.define = function (protoProps, staticProps) { + if (protoProps === void 0) { protoProps = {}; } + var BaseClass = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["getBaseClass"])(this); + staticProps && Object(_tools__WEBPACK_IMPORTED_MODULE_1__["assign"])(this, staticProps); + var mixins = protoProps.mixins, defineMixin = tslib__WEBPACK_IMPORTED_MODULE_0__["__rest"](protoProps, ["mixins"]); + mixins && this.mixins.merge(mixins); + this.mixins.mergeObject(this.prototype, defineMixin, true); + this.mixins.mergeObject(this.prototype, this.mixins.getStaticDefinitions(BaseClass), true); + this.onDefine && this.onDefine(this.mixins.definitions, BaseClass); + this.mixins.mergeInheritedMembers(BaseClass); + return this; + }; + Mixable.extend = function (spec, statics) { + var TheSubclass; + if (spec && spec.hasOwnProperty('constructor')) { + TheSubclass = spec.constructor; + Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TheSubclass, this); + } + else { + TheSubclass = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](Subclass, _super); + function Subclass() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Subclass; + }(this)); + } + predefine(TheSubclass); + spec && TheSubclass.define(spec, statics); + return TheSubclass; + }; + return Mixable; +}()); + +function predefine(Constructor) { + var BaseClass = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["getBaseClass"])(Constructor); + Constructor.__super__ = BaseClass.prototype; + Constructor.define || MixinsState.get(Mixable).populate(Constructor); + MixinsState.get(Constructor); + Constructor.onExtend && Constructor.onExtend(BaseClass); +} +function define(ClassOrDefinition) { + if (typeof ClassOrDefinition === 'function') { + predefine(ClassOrDefinition); + ClassOrDefinition.define(); + } + else { + return function (Ctor) { + predefine(Ctor); + Ctor.define(ClassOrDefinition); + }; + } +} +function definitions(rules) { + return function (Class) { + var mixins = MixinsState.get(Class); + mixins.definitionRules = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])(Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(), rules, mixins.definitionRules); + }; +} +function propertyListDecorator(listName) { + return function propList(proto, name) { + var list = proto.hasOwnProperty(listName) ? + proto[listName] : (proto[listName] = (proto[listName] || []).slice()); + list.push(name); + }; +} +function definitionDecorator(definitionKey, value) { + return function (proto, name) { + var _a, _b; + MixinsState + .get(proto.constructor) + .mergeObject(proto, (_a = {}, + _a[definitionKey] = (_b = {}, + _b[name] = value, + _b), + _a)); + }; +} +var MixinsState = (function () { + function MixinsState(Class) { + this.Class = Class; + this.definitions = {}; + var mixins = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["getBaseClass"])(Class).mixins; + this.mergeRules = (mixins && mixins.mergeRules) || Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(); + this.definitionRules = (mixins && mixins.definitionRules) || Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(); + this.appliedMixins = (mixins && mixins.appliedMixins) || []; + } + MixinsState.get = function (Class) { + var mixins = Class.mixins; + return mixins && Class === mixins.Class ? mixins : + Class.mixins = new MixinsState(Class); + }; + MixinsState.prototype.getStaticDefinitions = function (BaseClass) { + var definitions = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(), Class = this.Class; + return Object(_tools__WEBPACK_IMPORTED_MODULE_1__["transform"])(definitions, this.definitionRules, function (rule, name) { + if (BaseClass[name] !== Class[name]) { + return Class[name]; + } + }); + }; + MixinsState.prototype.merge = function (mixins) { + var proto = this.Class.prototype, mergeRules = this.mergeRules; + var appliedMixins = this.appliedMixins = this.appliedMixins.slice(); + for (var _i = 0, mixins_1 = mixins; _i < mixins_1.length; _i++) { + var mixin = mixins_1[_i]; + if (Array.isArray(mixin)) { + this.merge(mixin); + } + else if (appliedMixins.indexOf(mixin) < 0) { + appliedMixins.push(mixin); + if (typeof mixin === 'function') { + this.mergeObject(this.Class, mixin); + var sourceMixins = mixin.mixins; + if (sourceMixins) { + this.mergeRules = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])(Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(), this.mergeRules, sourceMixins.mergeRules); + this.definitionRules = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])(Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])(), this.definitionRules, sourceMixins.definitionRules); + this.appliedMixins = this.appliedMixins.concat(sourceMixins.appliedMixins); + } + this.mergeObject(proto, mixin.prototype); + } + else { + this.mergeObject(proto, mixin); + } + } + } + }; + MixinsState.prototype.populate = function () { + var ctors = []; + for (var _i = 0; _i < arguments.length; _i++) { + ctors[_i] = arguments[_i]; + } + for (var _a = 0, ctors_1 = ctors; _a < ctors_1.length; _a++) { + var Ctor = ctors_1[_a]; + MixinsState.get(Ctor).merge([this.Class]); + } + }; + MixinsState.prototype.mergeObject = function (dest, source, unshift) { + var _this = this; + forEachOwnProp(source, function (name) { + var sourceProp = Object.getOwnPropertyDescriptor(source, name); + var rule; + if (rule = _this.definitionRules[name]) { + assignProperty(_this.definitions, name, sourceProp, rule, unshift); + } + if (!rule || rule === mixinRules.protoValue) { + assignProperty(dest, name, sourceProp, _this.mergeRules[name], unshift); + } + }); + }; + MixinsState.prototype.mergeInheritedMembers = function (BaseClass) { + var _a = this, mergeRules = _a.mergeRules, Class = _a.Class; + if (mergeRules) { + var proto = Class.prototype, baseProto = BaseClass.prototype; + for (var name_1 in mergeRules) { + var rule = mergeRules[name_1]; + if (proto.hasOwnProperty(name_1) && name_1 in baseProto) { + proto[name_1] = resolveRule(proto[name_1], baseProto[name_1], rule); + } + } + } + }; + return MixinsState; +}()); + +var dontMix = { + function: Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])({ + length: true, + prototype: true, + caller: true, + arguments: true, + name: true, + __super__: true + }), + object: Object(_tools__WEBPACK_IMPORTED_MODULE_1__["hashMap"])({ + constructor: true + }) +}; +function forEachOwnProp(object, fun) { + var ignore = dontMix[typeof object]; + for (var _i = 0, _a = Object.getOwnPropertyNames(object); _i < _a.length; _i++) { + var name_2 = _a[_i]; + ignore[name_2] || fun(name_2); + } +} +var mixins = function () { + var list = []; + for (var _i = 0; _i < arguments.length; _i++) { + list[_i] = arguments[_i]; + } + return (function (Class) { return MixinsState.get(Class).merge(list); }); +}; +var mixinRules = (function (rules) { return (function (Class) { + var mixins = MixinsState.get(Class); + mixins.mergeRules = Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])(rules, mixins.mergeRules); +}); }); +mixinRules.value = function (a, b) { return a; }; +mixinRules.protoValue = function (a, b) { return a; }; +mixinRules.merge = function (a, b) { return Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])({}, a, b); }; +mixinRules.pipe = function (a, b) { return (function (x) { + return a.call(this, b.call(this, x)); +}); }; +mixinRules.defaults = function (a, b) { return (function () { + return Object(_tools__WEBPACK_IMPORTED_MODULE_1__["defaults"])(a.apply(this, arguments), b.apply(this, arguments)); +}); }; +mixinRules.classFirst = function (a, b) { return (function () { + a.apply(this, arguments); + b.apply(this, arguments); +}); }; +mixinRules.classLast = function (a, b) { return (function () { + b.apply(this, arguments); + a.apply(this, arguments); +}); }; +mixinRules.every = function (a, b) { return (function () { + return a.apply(this, arguments) && b.apply(this, arguments); +}); }; +mixinRules.some = function (a, b) { return (function () { + return a.apply(this, arguments) || b.apply(this, arguments); +}); }; +function assignProperty(dest, name, sourceProp, rule, unshift) { + if (dest.hasOwnProperty(name)) { + var destProp = Object.getOwnPropertyDescriptor(dest, name); + if (destProp.configurable && 'value' in destProp) { + dest[name] = unshift ? + resolveRule(sourceProp.value, destProp.value, rule) : + resolveRule(destProp.value, sourceProp.value, rule); + } + } + else { + Object.defineProperty(dest, name, sourceProp); + } +} +function resolveRule(dest, source, rule) { + if (dest === void 0) + return source; + if (!rule || source === void 0) + return dest; + return rule(dest, source); +} + + +/***/ }), + +/***/ "../../mixture/lib/tools.js": +/*!***********************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/mixture/lib/tools.js ***! + \***********************************************************/ +/*! exports provided: defaults, isValidJSON, getBaseClass, assignToClassProto, isEmpty, some, every, getPropertyDescriptor, omit, transform, fastAssign, fastDefaults, assign, keys, once, notEqual, hashMap */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaults", function() { return defaults; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isValidJSON", function() { return isValidJSON; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBaseClass", function() { return getBaseClass; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "assignToClassProto", function() { return assignToClassProto; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return isEmpty; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "some", function() { return some; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "every", function() { return every; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getPropertyDescriptor", function() { return getPropertyDescriptor; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "omit", function() { return omit; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transform", function() { return transform; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fastAssign", function() { return fastAssign; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fastDefaults", function() { return fastDefaults; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "assign", function() { return assign; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "keys", function() { return keys; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "once", function() { return once; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "notEqual", function() { return notEqual; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hashMap", function() { return hashMap; }); +function defaults(dest, source) { + for (var name in source) { + if (source.hasOwnProperty(name) && !dest.hasOwnProperty(name)) { + dest[name] = source[name]; + } + } + if (arguments.length > 2) { + for (var i = 2; i < arguments.length; i++) { + var other = arguments[i]; + other && defaults(dest, other); + } + } + return dest; +} +function isValidJSON(value) { + if (value === null) { + return true; + } + switch (typeof value) { + case 'number': + case 'string': + case 'boolean': + return true; + case 'object': + var proto = Object.getPrototypeOf(value); + if (proto === Object.prototype || proto === Array.prototype) { + return every(value, isValidJSON); + } + } + return false; +} +function getBaseClass(Class) { + return Object.getPrototypeOf(Class.prototype).constructor; +} +function assignToClassProto(Class, definition) { + var names = []; + for (var _i = 2; _i < arguments.length; _i++) { + names[_i - 2] = arguments[_i]; + } + for (var _a = 0, names_1 = names; _a < names_1.length; _a++) { + var name_1 = names_1[_a]; + var value = definition[name_1]; + value === void 0 || (Class.prototype[name_1] = value); + } +} +function isEmpty(obj) { + if (obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + return false; + } + } + } + return true; +} +function someArray(arr, fun) { + var result; + for (var i = 0; i < arr.length; i++) { + if (result = fun(arr[i], i)) { + return result; + } + } +} +function someObject(obj, fun) { + var result; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (result = fun(obj[key], key)) { + return result; + } + } + } +} +function some(obj, fun) { + if (Object.getPrototypeOf(obj) === ArrayProto) { + return someArray(obj, fun); + } + else { + return someObject(obj, fun); + } +} +function every(obj, predicate) { + return !some(obj, function (x) { return !predicate(x); }); +} +function getPropertyDescriptor(obj, prop) { + var desc; + for (var proto = obj; !desc && proto; proto = Object.getPrototypeOf(proto)) { + desc = Object.getOwnPropertyDescriptor(proto, prop); + } + return desc; +} +function omit(source) { + var dest = {}, discard = {}; + for (var i = 1; i < arguments.length; i++) { + discard[arguments[i]] = true; + } + for (var name in source) { + if (!discard.hasOwnProperty(name) && source.hasOwnProperty(name)) { + dest[name] = source[name]; + } + } + return dest; +} +function transform(dest, source, fun) { + for (var name in source) { + if (source.hasOwnProperty(name)) { + var value = fun(source[name], name); + value === void 0 || (dest[name] = value); + } + } + return dest; +} +function fastAssign(dest, source) { + for (var name in source) { + dest[name] = source[name]; + } + return dest; +} +function fastDefaults(dest, source) { + for (var name in source) { + if (dest[name] === void 0) { + dest[name] = source[name]; + } + } + return dest; +} +function assign(dest, source) { + for (var name in source) { + if (source.hasOwnProperty(name)) { + dest[name] = source[name]; + } + } + if (arguments.length > 2) { + for (var i = 2; i < arguments.length; i++) { + var other = arguments[i]; + other && assign(dest, other); + } + } + return dest; +} +function keys(o) { + return o ? Object.keys(o) : []; +} +function once(func) { + var memo, first = true; + return function () { + if (first) { + first = false; + memo = func.apply(this, arguments); + func = null; + } + return memo; + }; +} +var ArrayProto = Array.prototype, DateProto = Date.prototype, ObjectProto = Object.prototype; +function notEqual(a, b) { + if (a === b) + return false; + if (a && b && typeof a == 'object' && typeof b == 'object') { + var protoA = Object.getPrototypeOf(a); + if (protoA !== Object.getPrototypeOf(b)) + return true; + switch (protoA) { + case DateProto: return +a !== +b; + case ArrayProto: return arraysNotEqual(a, b); + case ObjectProto: + case null: + return objectsNotEqual(a, b); + } + } + return true; +} +function objectsNotEqual(a, b) { + var keysA = Object.keys(a); + if (keysA.length !== Object.keys(b).length) + return true; + for (var i = 0; i < keysA.length; i++) { + var key = keysA[i]; + if (!b.hasOwnProperty(key) || notEqual(a[key], b[key])) { + return true; + } + } + return false; +} +function arraysNotEqual(a, b) { + if (a.length !== b.length) + return true; + for (var i = 0; i < a.length; i++) { + if (notEqual(a[i], b[i])) + return true; + } + return false; +} +var HashProto = Object.create(null); +HashProto.hasOwnProperty = ObjectProto.hasOwnProperty; +function hashMap(obj) { + var hash = Object.create(HashProto); + return obj ? assign(hash, obj) : hash; +} + + +/***/ }), + +/***/ "../../models/lib/collection/add.js": +/*!*******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/add.js ***! + \*******************************************************************/ +/*! exports provided: addTransaction */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addTransaction", function() { return addTransaction; }); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./commons */ "../../models/lib/collection/commons.js"); + + +var begin = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].begin, commit = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].commit, markAsDirty = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].markAsDirty; +function addTransaction(collection, items, options, merge) { + var isRoot = begin(collection), nested = []; + var added = appendElements(collection, items, nested, options, merge); + if (added.length || nested.length) { + var needSort = sortOrMoveElements(collection, added, options); + if (markAsDirty(collection, options)) { + return new _commons__WEBPACK_IMPORTED_MODULE_1__["CollectionTransaction"](collection, isRoot, added, [], nested, needSort); + } + if (collection._aggregationError) + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["logAggregationError"])(collection, options); + } + isRoot && commit(collection); +} +; +function sortOrMoveElements(collection, added, options) { + var at = options.at; + if (at != null) { + var length_1 = collection.models.length - added.length; + at = Number(at); + if (at < 0) + at += length_1 + 1; + if (at < 0) + at = 0; + if (at > length_1) + at = length_1; + moveElements(collection.models, at, added); + return false; + } + return Object(_commons__WEBPACK_IMPORTED_MODULE_1__["sortElements"])(collection, options); +} +function moveElements(source, at, added) { + for (var j = source.length - 1, i = j - added.length; i >= at; i--, j--) { + source[j] = source[i]; + } + for (i = 0, j = at; i < added.length; i++, j++) { + source[j] = added[i]; + } +} +function appendElements(collection, a_items, nested, a_options, forceMerge) { + var _byId = collection._byId, models = collection.models, merge = (forceMerge || a_options.merge) && !collection._shared, parse = a_options.parse, idAttribute = collection.model.prototype.idAttribute, prevLength = models.length; + for (var _i = 0, a_items_1 = a_items; _i < a_items_1.length; _i++) { + var item = a_items_1[_i]; + var model = item ? _byId[item[idAttribute]] || _byId[item.cid] : null; + if (model) { + if (merge && item !== model) { + var attrs = item.attributes || item; + var transaction = model._createTransaction(attrs, a_options); + transaction && nested.push(transaction); + if (model.hasChanged(idAttribute)) { + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["updateIndex"])(_byId, model); + } + } + } + else { + model = Object(_commons__WEBPACK_IMPORTED_MODULE_1__["convertAndAquire"])(collection, item, a_options); + models.push(model); + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["addIndex"])(_byId, model); + } + } + return models.slice(prevLength); +} + + +/***/ }), + +/***/ "../../models/lib/collection/arrayMethods.js": +/*!****************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/arrayMethods.js ***! + \****************************************************************************/ +/*! exports provided: ArrayMixin */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayMixin", function() { return ArrayMixin; }); +var ArrayMixin = (function () { + function ArrayMixin() { + } + ArrayMixin.prototype.map = function (mapFilter, context) { + var models = this.models, length = models.length, res = Array(length), fun = context ? mapFilter.bind(context) : mapFilter; + for (var i = 0, j = 0; i < length; i++) { + var val = fun(models[i], i); + val === void 0 || (res[j++] = val); + } + if (i !== j) { + res.length = j; + } + return res; + }; + ArrayMixin.prototype.each = function (fun, context) { + var models = this.models, length = models.length, iteratee = context ? fun.bind(context) : fun; + for (var i = 0; i < length; i++) { + iteratee(models[i], i); + } + }; + ArrayMixin.prototype.firstMatch = function (doWhile, context) { + var models = this.models, length = models.length, iteratee = context ? doWhile.bind(context) : doWhile; + for (var i = 0; i < length; i++) { + var res = iteratee(models[i], i); + if (res !== void 0) + return res; + } + }; + ArrayMixin.prototype.reduce = function (iteratee, init) { + return init === void 0 ? this.models.reduce(iteratee) : this.models.reduce(iteratee, init); + }; + ArrayMixin.prototype.slice = function (begin, end) { + return this.models.slice(begin, end); + }; + ArrayMixin.prototype.indexOf = function (modelOrId) { + return this.models.indexOf(this.get(modelOrId)); + }; + ArrayMixin.prototype.includes = function (idOrObj) { + return Boolean(this.get(idOrObj)); + }; + ArrayMixin.prototype.filter = function (iteratee, context) { + var fun = toPredicateFunction(iteratee); + return this.map(function (m) { return fun(m) ? m : void 0; }, context); + }; + ArrayMixin.prototype.find = function (iteratee, context) { + var fun = toPredicateFunction(iteratee); + return this.firstMatch(function (m) { return fun(m) ? m : void 0; }, context); + }; + ArrayMixin.prototype.some = function (iteratee, context) { + return Boolean(this.find(iteratee, context)); + }; + ArrayMixin.prototype.forEach = function (iteratee, context) { + this.each(iteratee, context); + }; + ArrayMixin.prototype.values = function () { + return this.models.values(); + }; + ArrayMixin.prototype.entries = function () { + return this.models.entries(); + }; + ArrayMixin.prototype.every = function (iteratee, context) { + var fun = toPredicateFunction(iteratee); + return this.firstMatch(function (m) { return fun(m) ? void 0 : false; }, context) === void 0; + }; + ArrayMixin.prototype.pluck = function (key) { + return this.map(function (model) { return model[key]; }); + }; + ArrayMixin.prototype.first = function () { return this.models[0]; }; + ArrayMixin.prototype.last = function () { return this.models[this.models.length - 1]; }; + ArrayMixin.prototype.at = function (a_index) { + var index = a_index < 0 ? a_index + this.models.length : a_index; + return this.models[index]; + }; + return ArrayMixin; +}()); + +var noOp = function (x) { return x; }; +function toPredicateFunction(iteratee) { + if (iteratee == null) + return noOp; + switch (typeof iteratee) { + case 'function': return iteratee; + case 'object': + var keys_1 = Object.keys(iteratee); + return function (x) { + for (var _i = 0, keys_2 = keys_1; _i < keys_2.length; _i++) { + var key = keys_2[_i]; + if (iteratee[key] !== x[key]) + return false; + } + return true; + }; + default: throw new Error('Invalid iteratee'); + } +} + + +/***/ }), + +/***/ "../../models/lib/collection/commons.js": +/*!***********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/commons.js ***! + \***********************************************************************/ +/*! exports provided: dispose, convertAndAquire, free, freeAll, sortElements, addIndex, removeIndex, updateIndex, CollectionTransaction, logAggregationError */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dispose", function() { return dispose; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "convertAndAquire", function() { return convertAndAquire; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "free", function() { return free; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "freeAll", function() { return freeAll; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sortElements", function() { return sortElements; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addIndex", function() { return addIndex; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeIndex", function() { return removeIndex; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "updateIndex", function() { return updateIndex; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollectionTransaction", function() { return CollectionTransaction; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "logAggregationError", function() { return logAggregationError; }); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); + + +var trigger2 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].trigger2, trigger3 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].trigger3, on = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].on, off = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].off, commit = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].commit, _aquire = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].aquire, _free = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].free; +function dispose(collection) { + var models = collection.models; + collection.models = []; + collection._byId = {}; + freeAll(collection, models); + return models; +} +function convertAndAquire(collection, attrs, options) { + var model = collection.model; + var record; + if (collection._shared) { + record = attrs instanceof model ? attrs : model.create(attrs, options); + if (collection._shared & _transactions__WEBPACK_IMPORTED_MODULE_1__["ItemsBehavior"].listen) { + on(record, record._changeEventName, collection._onChildrenChange, collection); + } + } + else { + record = attrs instanceof model ? (options.merge ? attrs.clone() : attrs) : model.create(attrs, options); + if (record._owner) { + if (record._owner !== collection) { + _aquire(collection, record.clone()); + var errors = collection._aggregationError || (collection._aggregationError = []); + errors.push(record); + } + } + else { + _aquire(collection, record); + } + } + var _itemEvents = collection._itemEvents; + _itemEvents && _itemEvents.subscribe(collection, record); + return record; +} +function free(owner, child, unset) { + if (owner._shared) { + if (owner._shared & _transactions__WEBPACK_IMPORTED_MODULE_1__["ItemsBehavior"].listen) { + off(child, child._changeEventName, owner._onChildrenChange, owner); + } + } + else { + _free(owner, child); + unset || child.dispose(); + } + var _itemEvents = owner._itemEvents; + _itemEvents && _itemEvents.unsubscribe(owner, child); +} +function freeAll(collection, children) { + for (var _i = 0, children_1 = children; _i < children_1.length; _i++) { + var child = children_1[_i]; + free(collection, child); + } + return children; +} +function sortElements(collection, options) { + var _comparator = collection._comparator; + if (_comparator && options.sort !== false) { + collection.models.sort(_comparator); + return true; + } + return false; +} +function addIndex(index, model) { + index[model.cid] = model; + var id = model.id; + if (id || id === 0) { + index[id] = model; + } +} +function removeIndex(index, model) { + delete index[model.cid]; + var id = model.id; + if (id || id === 0) { + delete index[id]; + } +} +function updateIndex(index, model) { + delete index[model.previous(model.idAttribute)]; + var id = model.id; + id == null || (index[id] = model); +} +var CollectionTransaction = (function () { + function CollectionTransaction(object, isRoot, added, removed, nested, sorted) { + this.object = object; + this.isRoot = isRoot; + this.added = added; + this.removed = removed; + this.nested = nested; + this.sorted = sorted; + } + CollectionTransaction.prototype.commit = function (initiator) { + var _a = this, nested = _a.nested, object = _a.object, _isDirty = object._isDirty; + for (var _i = 0, nested_1 = nested; _i < nested_1.length; _i++) { + var transaction = nested_1[_i]; + transaction.commit(object); + } + if (object._aggregationError) { + logAggregationError(object, _isDirty); + } + for (var _b = 0, nested_2 = nested; _b < nested_2.length; _b++) { + var transaction = nested_2[_b]; + trigger2(object, 'change', transaction.object, _isDirty); + } + var _c = this, added = _c.added, removed = _c.removed; + for (var _d = 0, added_1 = added; _d < added_1.length; _d++) { + var record = added_1[_d]; + trigger3(record, 'add', record, object, _isDirty); + trigger3(object, 'add', record, object, _isDirty); + } + for (var _e = 0, removed_1 = removed; _e < removed_1.length; _e++) { + var record = removed_1[_e]; + trigger3(record, 'remove', record, object, _isDirty); + trigger3(object, 'remove', record, object, _isDirty); + } + if (this.sorted) { + trigger2(object, 'sort', object, _isDirty); + } + if (added.length || removed.length) { + trigger2(object, 'update', object, _isDirty); + } + this.isRoot && commit(object, initiator); + }; + return CollectionTransaction; +}()); + +function logAggregationError(collection, options) { + collection._log('warn', 'Type-R:InvalidOwner', 'added records already have an owner and were cloned. Use explicit record.clone() to dismiss this warning.', collection._aggregationError, options.logger); + collection._aggregationError = void 0; +} + + +/***/ }), + +/***/ "../../models/lib/collection/index.js": +/*!*********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/index.js ***! + \*********************************************************************/ +/*! exports provided: Collection */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Collection", function() { return Collection; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _io_tools__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../io-tools */ "../../models/lib/io-tools.js"); +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../model */ "../../models/lib/model/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _add__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./add */ "../../models/lib/collection/add.js"); +/* harmony import */ var _arrayMethods__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./arrayMethods */ "../../models/lib/collection/arrayMethods.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./commons */ "../../models/lib/collection/commons.js"); +/* harmony import */ var _remove__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./remove */ "../../models/lib/collection/remove.js"); +/* harmony import */ var _set__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./set */ "../../models/lib/collection/set.js"); + + + + + + + + + + + +var trigger2 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["eventsApi"].trigger2, begin = _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"].begin, commit = _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"].commit, markAsDirty = _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"].markAsDirty; +var _count = 0; +var CollectionRefsType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CollectionRefsType, _super); + function CollectionRefsType() { + return _super !== null && _super.apply(this, arguments) || this; + } + CollectionRefsType.defaultValue = []; + return CollectionRefsType; +}(_model__WEBPACK_IMPORTED_MODULE_4__["SharedType"])); +; +var Collection = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](Collection, _super); + function Collection(records, options, shared) { + if (options === void 0) { options = {}; } + var _this = _super.call(this, _count++) || this; + _this.models = []; + _this._byId = {}; + _this.comparator = _this.comparator; + if (options.comparator !== void 0) { + _this.comparator = options.comparator; + options.comparator = void 0; + } + _this.model = _this.model; + if (options.model) { + _this.model = options.model; + options.model = void 0; + } + _this.idAttribute = _this.model.prototype.idAttribute; + _this._shared = shared || 0; + if (records) { + var elements = toElements(_this, records, options); + Object(_set__WEBPACK_IMPORTED_MODULE_10__["emptySetTransaction"])(_this, elements, options, true); + } + _this.initialize.apply(_this, arguments); + if (_this._localEvents) + _this._localEvents.subscribe(_this, _this); + return _this; + } + Collection_1 = Collection; + Collection.of = function (Ctor) { + return Ctor.Collection; + }; + Collection.ofRefs = function (Ctor) { + return Ctor.Collection.Refs; + }; + Collection.prototype.createSubset = function (models, options) { + throw new ReferenceError('Failed dependency injection'); + }; + Collection.onExtend = function (BaseClass) { + var Ctor = this; + this._SubsetOf = null; + function RefsCollection(a, b, listen) { + Ctor.call(this, a, b, _transactions__WEBPACK_IMPORTED_MODULE_5__["ItemsBehavior"].share | (listen ? _transactions__WEBPACK_IMPORTED_MODULE_5__["ItemsBehavior"].listen : 0)); + } + _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["Mixable"].mixins.populate(RefsCollection); + RefsCollection.prototype = this.prototype; + RefsCollection._metatype = CollectionRefsType; + this.Refs = this.Subset = RefsCollection; + _transactions__WEBPACK_IMPORTED_MODULE_5__["Transactional"].onExtend.call(this, BaseClass); + }; + Collection.onDefine = function (definition, BaseClass) { + if (definition.itemEvents) { + var eventsMap = new _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["EventMap"](BaseClass.prototype._itemEvents); + eventsMap.addEventsMap(definition.itemEvents); + this.prototype._itemEvents = eventsMap; + } + if (definition.comparator !== void 0) + this.prototype.comparator = definition.comparator; + _transactions__WEBPACK_IMPORTED_MODULE_5__["Transactional"].onDefine.call(this, definition); + }; + Object.defineProperty(Collection.prototype, "__inner_state__", { + get: function () { return this.models; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Collection.prototype, "comparator", { + get: function () { return this._comparator; }, + set: function (x) { + var _this = this; + switch (typeof x) { + case 'string': + this._comparator = function (a, b) { + var aa = a[x], bb = b[x]; + if (aa === bb) + return 0; + return aa < bb ? -1 : +1; + }; + break; + case 'function': + if (x.length === 1) { + this._comparator = function (a, b) { + var aa = x.call(_this, a), bb = x.call(_this, b); + if (aa === bb) + return 0; + return aa < bb ? -1 : +1; + }; + } + else { + this._comparator = function (a, b) { return x.call(_this, a, b); }; + } + break; + default: + this._comparator = null; + } + }, + enumerable: true, + configurable: true + }); + Collection.prototype.getStore = function () { + return this._store || (this._store = this._owner ? this._owner.getStore() : this._defaultStore); + }; + Collection.prototype._onChildrenChange = function (record, options, initiator) { + if (options === void 0) { options = {}; } + if (initiator === this) + return; + var idAttribute = this.idAttribute; + if (record.hasChanged(idAttribute)) { + Object(_commons__WEBPACK_IMPORTED_MODULE_8__["updateIndex"])(this._byId, record); + } + var isRoot = begin(this); + if (markAsDirty(this, options)) { + trigger2(this, 'change', record, options); + } + isRoot && commit(this); + }; + Collection.prototype.get = function (objOrId) { + if (objOrId == null) + return; + if (typeof objOrId === 'object') { + var id = objOrId[this.idAttribute]; + return (id !== void 0 && this._byId[id]) || this._byId[objOrId.cid]; + } + else { + return this._byId[objOrId]; + } + }; + Collection.prototype[Symbol.iterator] = function () { + return this.models[Symbol.iterator](); + }; + Collection.prototype.updateEach = function (iteratee) { + var isRoot = _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"].begin(this); + this.each(iteratee); + isRoot && _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"].commit(this); + }; + Collection.prototype._validateNested = function (errors) { + if (this._shared) + return 0; + var count = 0; + this.each(function (record) { + var error = record.validationError; + if (error) { + errors[record.cid] = error; + count++; + } + }); + return count; + }; + Collection.prototype.initialize = function () { }; + Collection.prototype.clone = function (options) { + if (options === void 0) { options = {}; } + var models = this._shared & _transactions__WEBPACK_IMPORTED_MODULE_5__["ItemsBehavior"].share ? this.models : this.map(function (model) { return model.clone(); }), copy = new this.constructor(models, { model: this.model, comparator: this.comparator }, this._shared); + if (options.pinStore) + copy._defaultStore = this.getStore(); + return copy; + }; + Collection.prototype.toJSON = function (options) { + return this.map(function (model) { return model.toJSON(options); }); + }; + Collection.prototype.set = function (elements, options) { + if (elements === void 0) { elements = []; } + if (options === void 0) { options = {}; } + if (options.add !== void 0) { + this._log('warn', "Type-R:InvalidOption", "Collection.set doesn't support 'add' option, behaving as if options.add === true.", options); + } + if (options.reset) { + this.reset(elements, options); + } + else { + var transaction = this._createTransaction(elements, options); + transaction && transaction.commit(); + } + return this; + }; + Collection.prototype.liveUpdates = function (enabled) { + var _this = this; + if (enabled) { + this.liveUpdates(false); + var filter_1 = typeof enabled === 'function' ? enabled : function () { return true; }; + this._liveUpdates = { + updated: function (json) { + filter_1(json) && _this.add(json, { parse: true, merge: true }); + }, + removed: function (id) { return _this.remove(id); } + }; + return this.getEndpoint().subscribe(this._liveUpdates, this).then(function () { return _this; }); + } + else { + if (this._liveUpdates) { + this.getEndpoint().unsubscribe(this._liveUpdates, this); + this._liveUpdates = null; + } + } + }; + Collection.prototype.fetch = function (a_options) { + var _this = this; + if (a_options === void 0) { a_options = {}; } + var options = tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ parse: true }, a_options), endpoint = this.getEndpoint(); + return Object(_io_tools__WEBPACK_IMPORTED_MODULE_3__["startIO"])(this, endpoint.list(options, this), options, function (json) { + var result = _this.set(json, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ parse: true, ioMethod: 'fetch' }, options)); + if (options.liveUpdates) { + result = _this.liveUpdates(options.liveUpdates); + } + return result; + }); + }; + Collection.prototype.dispose = function () { + if (this._disposed) + return; + var aggregated = !this._shared; + for (var _i = 0, _a = this.models; _i < _a.length; _i++) { + var record = _a[_i]; + Object(_commons__WEBPACK_IMPORTED_MODULE_8__["free"])(this, record); + if (aggregated) + record.dispose(); + } + this.liveUpdates(false); + _super.prototype.dispose.call(this); + }; + Collection.prototype.reset = function (a_elements, options) { + if (options === void 0) { options = {}; } + var isRoot = begin(this), previousModels = this.models; + if (a_elements) { + Object(_set__WEBPACK_IMPORTED_MODULE_10__["emptySetTransaction"])(this, toElements(this, a_elements, options), options, true); + } + else { + this._byId = {}; + this.models = []; + } + markAsDirty(this, options); + options.silent || trigger2(this, 'reset', this, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ previousModels: previousModels }, options)); + var _byId = this._byId; + for (var _i = 0, previousModels_1 = previousModels; _i < previousModels_1.length; _i++) { + var toDispose = previousModels_1[_i]; + _byId[toDispose.cid] || Object(_commons__WEBPACK_IMPORTED_MODULE_8__["free"])(this, toDispose); + } + isRoot && commit(this); + return this.models; + }; + Collection.prototype.add = function (a_elements, options) { + if (options === void 0) { options = {}; } + var elements = toElements(this, a_elements, options), transaction = this.models.length ? + Object(_add__WEBPACK_IMPORTED_MODULE_6__["addTransaction"])(this, elements, options) : + Object(_set__WEBPACK_IMPORTED_MODULE_10__["emptySetTransaction"])(this, elements, options); + if (transaction) { + transaction.commit(); + return transaction.added; + } + }; + Collection.prototype.remove = function (recordsOrIds, options) { + if (options === void 0) { options = {}; } + if (recordsOrIds) { + return Array.isArray(recordsOrIds) ? + Object(_remove__WEBPACK_IMPORTED_MODULE_9__["removeMany"])(this, recordsOrIds, options) : + Object(_remove__WEBPACK_IMPORTED_MODULE_9__["removeOne"])(this, recordsOrIds, options); + } + return []; + }; + Collection.prototype.$includes = function (idOrObj) { + return new LinkedIncludes(this, idOrObj); + }; + Collection.prototype._createTransaction = function (a_elements, options) { + if (options === void 0) { options = {}; } + var elements = toElements(this, a_elements, options); + if (this.models.length) { + return options.remove === false ? + Object(_add__WEBPACK_IMPORTED_MODULE_6__["addTransaction"])(this, elements, options, true) : + Object(_set__WEBPACK_IMPORTED_MODULE_10__["setTransaction"])(this, elements, options); + } + else { + return Object(_set__WEBPACK_IMPORTED_MODULE_10__["emptySetTransaction"])(this, elements, options); + } + }; + Collection.prototype.sort = function (options) { + if (options === void 0) { options = {}; } + if (Object(_commons__WEBPACK_IMPORTED_MODULE_8__["sortElements"])(this, options)) { + var isRoot = begin(this); + if (markAsDirty(this, options)) { + trigger2(this, 'sort', this, options); + } + isRoot && commit(this); + } + return this; + }; + Collection.prototype.unset = function (modelOrId, options) { + var value = this.get(modelOrId); + this.remove(modelOrId, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ unset: true }, options)); + return value; + }; + Collection.prototype.modelId = function (attrs) { + return attrs[this.model.prototype.idAttribute]; + }; + Collection.prototype.toggle = function (model, a_next) { + var prev = Boolean(this.get(model)), next = a_next === void 0 ? !prev : Boolean(a_next); + if (prev !== next) { + if (prev) { + this.remove(model); + } + else { + this.add(model); + } + } + return next; + }; + Collection.prototype._log = function (level, topic, text, value, a_logger) { + (a_logger || _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["logger"]).trigger(level, topic, this.model.prototype.getClassName() + "." + this.getClassName() + ": " + text, { + Argument: value, + 'Attributes spec': this.model.prototype._attributes + }); + }; + Collection.prototype.getClassName = function () { + return _super.prototype.getClassName.call(this) || 'Collection'; + }; + Object.defineProperty(Collection.prototype, "length", { + get: function () { return this.models.length; }, + enumerable: true, + configurable: true + }); + Collection.prototype.push = function (model, options) { + return this.add(model, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ at: this.length }, options)); + }; + Collection.prototype.pop = function (options) { + var model = this.at(this.length - 1); + this.remove(model, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ unset: true }, options)); + return model; + }; + Collection.prototype.unshift = function (model, options) { + return this.add(model, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ at: 0 }, options)); + }; + Collection.prototype.shift = function (options) { + var model = this.at(0); + this.remove(model, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ unset: true }, options)); + return model; + }; + var Collection_1; + Collection.refsTo = _model__WEBPACK_IMPORTED_MODULE_4__["shared"]; + Collection._metatype = _model__WEBPACK_IMPORTED_MODULE_4__["AggregatedType"]; + Collection = Collection_1 = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["define"])({ + cidPrefix: 'c', + model: _model__WEBPACK_IMPORTED_MODULE_4__["Model"], + _changeEventName: 'changes', + _aggregationError: null + }), + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixins"])(_arrayMethods__WEBPACK_IMPORTED_MODULE_7__["ArrayMixin"]), + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["definitions"])({ + comparator: _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].value, + model: _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].protoValue, + itemEvents: _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].merge + }) + ], Collection); + return Collection; +}(_transactions__WEBPACK_IMPORTED_MODULE_5__["Transactional"])); + +function toElements(collection, elements, options) { + var parsed = options.parse ? collection.parse(elements, options) : elements; + return Array.isArray(parsed) ? parsed : [parsed]; +} +_model__WEBPACK_IMPORTED_MODULE_4__["Model"].Collection = Collection; +var LinkedIncludes = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](LinkedIncludes, _super); + function LinkedIncludes(collection, model) { + var _this = _super.call(this, collection.get(model)) || this; + _this.collection = collection; + _this.model = model; + return _this; + } + LinkedIncludes.prototype.set = function (x) { + this.collection.toggle(this.model); + }; + return LinkedIncludes; +}(_linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"])); + + +/***/ }), + +/***/ "../../models/lib/collection/remove.js": +/*!**********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/remove.js ***! + \**********************************************************************/ +/*! exports provided: removeOne, removeMany */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeOne", function() { return removeOne; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeMany", function() { return removeMany; }); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commons */ "../../models/lib/collection/commons.js"); + + + +var trigger2 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].trigger2, trigger3 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].trigger3, markAsDirty = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].markAsDirty, begin = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].begin, commit = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].commit; +function removeOne(collection, el, options) { + var model = collection.get(el); + if (model) { + var isRoot = begin(collection), models = collection.models; + models.splice(models.indexOf(model), 1); + Object(_commons__WEBPACK_IMPORTED_MODULE_2__["removeIndex"])(collection._byId, model); + var notify = markAsDirty(collection, options); + if (notify) { + trigger3(model, 'remove', model, collection, options); + trigger3(collection, 'remove', model, collection, options); + } + Object(_commons__WEBPACK_IMPORTED_MODULE_2__["free"])(collection, model, options.unset); + notify && trigger2(collection, 'update', collection, options); + isRoot && commit(collection); + return model; + } +} +; +function removeMany(collection, toRemove, options) { + var removed = _removeFromIndex(collection, toRemove, options.unset); + if (removed.length) { + var isRoot = begin(collection); + _reallocate(collection, removed.length); + if (markAsDirty(collection, options)) { + var transaction = new _commons__WEBPACK_IMPORTED_MODULE_2__["CollectionTransaction"](collection, isRoot, [], removed, [], false); + transaction.commit(); + } + else { + isRoot && commit(collection); + } + } + return removed; +} +; +function _removeFromIndex(collection, toRemove, unset) { + var removed = Array(toRemove.length), _byId = collection._byId; + for (var i = 0, j = 0; i < toRemove.length; i++) { + var model = collection.get(toRemove[i]); + if (model) { + removed[j++] = model; + Object(_commons__WEBPACK_IMPORTED_MODULE_2__["removeIndex"])(_byId, model); + Object(_commons__WEBPACK_IMPORTED_MODULE_2__["free"])(collection, model, unset); + } + } + removed.length = j; + return removed; +} +function _reallocate(collection, removed) { + var prev = collection.models, models = collection.models = Array(prev.length - removed), _byId = collection._byId; + for (var i = 0, j = 0; i < prev.length; i++) { + var model = prev[i]; + if (_byId[model.cid]) { + models[j++] = model; + } + } + models.length = j; +} + + +/***/ }), + +/***/ "../../models/lib/collection/set.js": +/*!*******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/collection/set.js ***! + \*******************************************************************/ +/*! exports provided: emptySetTransaction, setTransaction */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "emptySetTransaction", function() { return emptySetTransaction; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setTransaction", function() { return setTransaction; }); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./commons */ "../../models/lib/collection/commons.js"); + + +var begin = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].begin, commit = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].commit, markAsDirty = _transactions__WEBPACK_IMPORTED_MODULE_0__["transactionApi"].markAsDirty; +var silentOptions = { silent: true }; +function emptySetTransaction(collection, items, options, silent) { + var isRoot = begin(collection); + var added = _reallocateEmpty(collection, items, options); + if (added.length) { + var needSort = Object(_commons__WEBPACK_IMPORTED_MODULE_1__["sortElements"])(collection, options); + if (markAsDirty(collection, silent ? silentOptions : options)) { + return new _commons__WEBPACK_IMPORTED_MODULE_1__["CollectionTransaction"](collection, isRoot, added.slice(), [], [], needSort); + } + if (collection._aggregationError) + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["logAggregationError"])(collection, options); + } + isRoot && commit(collection); +} +; +function setTransaction(collection, items, options) { + var isRoot = begin(collection), nested = []; + var previous = collection.models, added = _reallocate(collection, items, nested, options); + var reusedCount = collection.models.length - added.length, removed = reusedCount < previous.length ? (reusedCount ? _garbageCollect(collection, previous) : + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["freeAll"])(collection, previous)) : []; + var addedOrChanged = nested.length || added.length, sorted = (Object(_commons__WEBPACK_IMPORTED_MODULE_1__["sortElements"])(collection, options) && addedOrChanged) || added.length || options.sorted; + if (addedOrChanged || removed.length || sorted) { + if (markAsDirty(collection, options)) { + return new _commons__WEBPACK_IMPORTED_MODULE_1__["CollectionTransaction"](collection, isRoot, added, removed, nested, sorted); + } + if (collection._aggregationError) + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["logAggregationError"])(collection, options); + } + isRoot && commit(collection); +} +; +function _garbageCollect(collection, previous) { + var _byId = collection._byId, removed = []; + for (var _i = 0, previous_1 = previous; _i < previous_1.length; _i++) { + var record = previous_1[_i]; + if (!_byId[record.cid]) { + removed.push(record); + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["free"])(collection, record); + } + } + return removed; +} +function _reallocate(collection, source, nested, options) { + var models = Array(source.length), _byId = {}, merge = (options.merge == null ? true : options.merge) && !collection._shared, _prevById = collection._byId, prevModels = collection.models, idAttribute = collection.model.prototype.idAttribute, toAdd = [], orderKept = true; + for (var i = 0, j = 0; i < source.length; i++) { + var item = source[i], model = null; + if (item) { + var id = item[idAttribute], cid = item.cid; + if (_byId[id] || _byId[cid]) + continue; + model = _prevById[id] || _prevById[cid]; + } + if (model) { + if (merge && item !== model) { + if (orderKept && prevModels[j] !== model) + orderKept = false; + var attrs = item.attributes || item; + var transaction = model._createTransaction(attrs, options); + transaction && nested.push(transaction); + } + } + else { + model = Object(_commons__WEBPACK_IMPORTED_MODULE_1__["convertAndAquire"])(collection, item, options); + toAdd.push(model); + } + models[j++] = model; + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["addIndex"])(_byId, model); + } + models.length = j; + collection.models = models; + collection._byId = _byId; + if (!orderKept) + options.sorted = true; + return toAdd; +} +function _reallocateEmpty(self, source, options) { + var len = source ? source.length : 0, models = Array(len), _byId = {}, idAttribute = self.model.prototype.idAttribute; + for (var i = 0, j = 0; i < len; i++) { + var src = source[i]; + if (src && (_byId[src[idAttribute]] || _byId[src.cid])) { + continue; + } + var model = Object(_commons__WEBPACK_IMPORTED_MODULE_1__["convertAndAquire"])(self, src, options); + models[j++] = model; + Object(_commons__WEBPACK_IMPORTED_MODULE_1__["addIndex"])(_byId, model); + } + models.length = j; + self._byId = _byId; + return self.models = models; +} + + +/***/ }), + +/***/ "../../models/lib/index.js": +/*!**********************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/index.js ***! + \**********************************************************/ +/*! exports provided: Record, Class, Linked, on, off, trigger, once, listenTo, stopListening, listenToOnce, transaction, Collection, getOwnerEndpoint, createIOPromise, startIO, abortIO, triggerAndBubble, tools, eventsApi, Model, attributes, auto, ItemsBehavior, Transactional, transactionApi, EventMap, Messenger, Events, isProduction, logEvents, Logger, logger, throwingLogger, log, Mixable, predefine, define, definitions, propertyListDecorator, definitionDecorator, MixinsState, mixins, mixinRules, ChainableAttributeSpec, type, shared, refTo, value, getMetatype, memberOf, subsetOf, Store, AnyType, ImmutableClassType, PrimitiveType, NumericType, ArrayType, ObjectType, doNothing, FunctionType, DateType, AggregatedType, SharedType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "on", function() { return on; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "off", function() { return off; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "trigger", function() { return trigger; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "once", function() { return once; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "listenTo", function() { return listenTo; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stopListening", function() { return stopListening; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "listenToOnce", function() { return listenToOnce; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transaction", function() { return transaction; }); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Class", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Mixable"]; }); + +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./model */ "../../models/lib/model/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Record", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["Model"]; }); + +/* harmony import */ var _collection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./collection */ "../../models/lib/collection/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Collection", function() { return _collection__WEBPACK_IMPORTED_MODULE_2__["Collection"]; }); + +/* harmony import */ var _io_tools__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./io-tools */ "../../models/lib/io-tools.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getOwnerEndpoint", function() { return _io_tools__WEBPACK_IMPORTED_MODULE_3__["getOwnerEndpoint"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "createIOPromise", function() { return _io_tools__WEBPACK_IMPORTED_MODULE_3__["createIOPromise"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startIO", function() { return _io_tools__WEBPACK_IMPORTED_MODULE_3__["startIO"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "abortIO", function() { return _io_tools__WEBPACK_IMPORTED_MODULE_3__["abortIO"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "triggerAndBubble", function() { return _io_tools__WEBPACK_IMPORTED_MODULE_3__["triggerAndBubble"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tools", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["tools"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "eventsApi", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EventMap", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["EventMap"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Messenger", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Messenger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Events", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Events"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isProduction", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["isProduction"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "logEvents", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["logEvents"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Logger", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Logger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "logger", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["logger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwingLogger", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["throwingLogger"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "log", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["log"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Mixable", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Mixable"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "predefine", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["predefine"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "define", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["define"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "definitions", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["definitions"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "propertyListDecorator", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["propertyListDecorator"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "definitionDecorator", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["definitionDecorator"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MixinsState", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["MixinsState"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mixins", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["mixins"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mixinRules", function() { return _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["mixinRules"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Model", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["Model"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "attributes", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["attributes"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auto", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["auto"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ChainableAttributeSpec", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["ChainableAttributeSpec"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "type", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["type"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shared", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["shared"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refTo", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["refTo"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "value", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["value"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getMetatype", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["getMetatype"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AnyType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["AnyType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ImmutableClassType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["ImmutableClassType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PrimitiveType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["PrimitiveType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "NumericType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["NumericType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ArrayType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["ArrayType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ObjectType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["ObjectType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "doNothing", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["doNothing"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FunctionType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["FunctionType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DateType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["DateType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AggregatedType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["AggregatedType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SharedType", function() { return _model__WEBPACK_IMPORTED_MODULE_1__["SharedType"]; }); + +/* harmony import */ var _relations__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./relations */ "../../models/lib/relations/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "memberOf", function() { return _relations__WEBPACK_IMPORTED_MODULE_4__["memberOf"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subsetOf", function() { return _relations__WEBPACK_IMPORTED_MODULE_4__["subsetOf"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Store", function() { return _relations__WEBPACK_IMPORTED_MODULE_4__["Store"]; }); + +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./transactions */ "../../models/lib/transactions.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ItemsBehavior", function() { return _transactions__WEBPACK_IMPORTED_MODULE_5__["ItemsBehavior"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Transactional", function() { return _transactions__WEBPACK_IMPORTED_MODULE_5__["Transactional"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "transactionApi", function() { return _transactions__WEBPACK_IMPORTED_MODULE_5__["transactionApi"]; }); + +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Linked", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_6__["Linked"]; }); + +var _a; +if (typeof Symbol === 'undefined') { + Object.defineProperty(window, 'Symbol', { value: { iterator: 'Symbol.iterator' }, configurable: true }); +} + + + + + + + + + + +var on = (_a = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["Events"], _a.on), off = _a.off, trigger = _a.trigger, once = _a.once, listenTo = _a.listenTo, stopListening = _a.stopListening, listenToOnce = _a.listenToOnce; +function transaction(method) { + return function () { + var _this = this; + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var result; + this.transaction(function () { + result = method.apply(_this, args); + }); + return result; + }; +} + + +/***/ }), + +/***/ "../../models/lib/io-tools.js": +/*!*************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/io-tools.js ***! + \*************************************************************/ +/*! exports provided: getOwnerEndpoint, createIOPromise, startIO, abortIO, triggerAndBubble */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getOwnerEndpoint", function() { return getOwnerEndpoint; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createIOPromise", function() { return createIOPromise; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startIO", function() { return startIO; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "abortIO", function() { return abortIO; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "triggerAndBubble", function() { return triggerAndBubble; }); +function getOwnerEndpoint(self) { + var collection = self.collection; + if (collection) { + return getOwnerEndpoint(collection); + } + if (self._owner) { + var _endpoints = self._owner._endpoints; + return _endpoints && _endpoints[self._ownerKey]; + } +} +function createIOPromise(initialize) { + var resolve, reject, onAbort; + function abort(fn) { + onAbort = fn; + } + var promise = new Promise(function (a_resolve, a_reject) { + reject = a_reject; + resolve = a_resolve; + initialize(resolve, reject, abort); + }); + promise.abort = function () { + onAbort ? onAbort(resolve, reject) : reject(new Error("I/O Aborted")); + }; + return promise; +} +function startIO(self, promise, options, thenDo) { + abortIO(self); + self._ioPromise = promise + .then(function (resp) { + self._ioPromise = null; + var result = thenDo ? thenDo(resp) : resp; + triggerAndBubble(self, 'sync', self, resp, options); + return result; + }) + .catch(function (err) { + self._ioPromise = null; + triggerAndBubble(self, 'error', self, err, options); + throw err; + }); + self._ioPromise.abort = promise.abort; + return self._ioPromise; +} +function abortIO(self) { + if (self._ioPromise && self._ioPromise.abort) { + self._ioPromise.abort(); + self._ioPromise = null; + } +} +function triggerAndBubble(eventSource) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + eventSource.trigger.apply(eventSource, args); + var collection = eventSource.collection; + collection && collection.trigger.apply(collection, args); +} + + +/***/ }), + +/***/ "../../models/lib/model/attrDef.js": +/*!******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/attrDef.js ***! + \******************************************************************/ +/*! exports provided: ChainableAttributeSpec, type, shared, refTo, value */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ChainableAttributeSpec", function() { return ChainableAttributeSpec; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "type", function() { return type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shared", function() { return shared; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "refTo", function() { return shared; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "value", function() { return value; }); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _metatypes__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./metatypes */ "../../models/lib/model/metatypes/index.js"); + + + +var assign = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["tools"].assign; +var ChainableAttributeSpec = (function () { + function ChainableAttributeSpec(options) { + this.options = { getHooks: [], transforms: [], changeHandlers: [] }; + if (options) + assign(this.options, options); + } + ChainableAttributeSpec.prototype.check = function (check, error) { + function validate(model, value, name) { + if (!check.call(model, value, name)) { + var msg = error || check.error || name + ' is not valid'; + return typeof msg === 'function' ? msg.call(model, name) : msg; + } + } + var prev = this.options.validate; + return this.metadata({ + validate: prev ? (function (model, value, name) { + return prev(model, value, name) || validate(model, value, name); + }) : validate + }); + }; + Object.defineProperty(ChainableAttributeSpec.prototype, "as", { + get: function () { + return Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["definitionDecorator"])('attributes', this); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(ChainableAttributeSpec.prototype, "isRequired", { + get: function () { + return this.required; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(ChainableAttributeSpec.prototype, "required", { + get: function () { + return this.metadata({ isRequired: true }); + }, + enumerable: true, + configurable: true + }); + ChainableAttributeSpec.prototype.endpoint = function (endpoint) { + return this.metadata({ endpoint: endpoint }); + }; + ChainableAttributeSpec.prototype.watcher = function (ref) { + return this.metadata({ _onChange: ref }); + }; + ChainableAttributeSpec.prototype.parse = function (fun) { + return this.metadata({ parse: fun }); + }; + ChainableAttributeSpec.prototype.toJSON = function (fun) { + return this.metadata({ + toJSON: typeof fun === 'function' ? fun : (fun ? function (x, k, o) { return x && x.toJSON(o); } : emptyFunction) + }); + }; + ChainableAttributeSpec.prototype.get = function (fun) { + return this.metadata({ + getHooks: this.options.getHooks.concat(fun) + }); + }; + ChainableAttributeSpec.prototype.set = function (fun) { + function handleSetHook(next, prev, record, options) { + if (this.isChanged(next, prev)) { + var changed = fun.call(record, next, this.name); + return changed === void 0 ? prev : this.convert(changed, prev, record, options); + } + return prev; + } + return this.metadata({ + transforms: this.options.transforms.concat(handleSetHook) + }); + }; + ChainableAttributeSpec.prototype.changeEvents = function (events) { + return this.metadata({ changeEvents: events }); + }; + ChainableAttributeSpec.prototype.events = function (map) { + var eventMap = new _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["EventMap"](map); + function handleEventsSubscribtion(next, prev, record) { + prev && prev.trigger && eventMap.unsubscribe(record, prev); + next && next.trigger && eventMap.subscribe(record, next); + } + return this.metadata({ + changeHandlers: this.options.changeHandlers.concat(handleEventsSubscribtion) + }); + }; + Object.defineProperty(ChainableAttributeSpec.prototype, "has", { + get: function () { + return this; + }, + enumerable: true, + configurable: true + }); + ChainableAttributeSpec.prototype.metadata = function (options) { + var cloned = new ChainableAttributeSpec(this.options); + assign(cloned.options, options); + return cloned; + }; + ChainableAttributeSpec.prototype.value = function (x) { + return this.metadata({ value: x, hasCustomDefault: true }); + }; + ChainableAttributeSpec.from = function (spec) { + if (spec && spec instanceof ChainableAttributeSpec) { + return spec; + } + return typeof spec === 'function' ? type(spec) : value(spec); + }; + return ChainableAttributeSpec; +}()); + +function emptyFunction() { } +function type(Type, value) { + if (Type instanceof ChainableAttributeSpec) + return Type; + var attrDef = new ChainableAttributeSpec({ type: Type }), defaultValue = Type && value === void 0 ? Object(_metatypes__WEBPACK_IMPORTED_MODULE_2__["getMetatype"])(Type).defaultValue : value; + return defaultValue === void 0 ? attrDef : attrDef.value(defaultValue); +} +function shared(Constructor) { + return new ChainableAttributeSpec({ + value: null, + type: Constructor, + _metatype: _metatypes__WEBPACK_IMPORTED_MODULE_2__["SharedType"] + }); +} + +function value(x) { + var Type = inferType(x), AttrDef = Type && Type.prototype instanceof _transactions__WEBPACK_IMPORTED_MODULE_1__["Transactional"] ? shared(Type) : + type(Type); + return AttrDef.value(x); +} +function inferType(value) { + switch (typeof value) { + case 'number': + return Number; + case 'string': + return String; + case 'boolean': + return Boolean; + case 'function': + return Function; + case 'undefined': + return void 0; + case 'object': + return value ? value.constructor : void 0; + } +} + + +/***/ }), + +/***/ "../../models/lib/model/index.js": +/*!****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/index.js ***! + \****************************************************************/ +/*! exports provided: Model, attributes, auto, ChainableAttributeSpec, type, shared, refTo, value, getMetatype, AnyType, ImmutableClassType, PrimitiveType, NumericType, ArrayType, ObjectType, doNothing, FunctionType, DateType, AggregatedType, SharedType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "attributes", function() { return attributes; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auto", function() { return auto; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _attrDef__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attrDef */ "../../models/lib/model/attrDef.js"); +/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mixin */ "../../models/lib/model/mixin.js"); +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./model */ "../../models/lib/model/model.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Model", function() { return _model__WEBPACK_IMPORTED_MODULE_5__["Model"]; }); + +/* harmony import */ var _linked_attrs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./linked-attrs */ "../../models/lib/model/linked-attrs.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ChainableAttributeSpec", function() { return _attrDef__WEBPACK_IMPORTED_MODULE_3__["ChainableAttributeSpec"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "type", function() { return _attrDef__WEBPACK_IMPORTED_MODULE_3__["type"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shared", function() { return _attrDef__WEBPACK_IMPORTED_MODULE_3__["shared"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refTo", function() { return _attrDef__WEBPACK_IMPORTED_MODULE_3__["refTo"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "value", function() { return _attrDef__WEBPACK_IMPORTED_MODULE_3__["value"]; }); + +/* harmony import */ var _metatypes__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./metatypes */ "../../models/lib/model/metatypes/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getMetatype", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["getMetatype"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AnyType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["AnyType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ImmutableClassType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["ImmutableClassType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PrimitiveType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["PrimitiveType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "NumericType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["NumericType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ArrayType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["ArrayType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ObjectType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["ObjectType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "doNothing", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["doNothing"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FunctionType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["FunctionType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DateType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["DateType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AggregatedType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["AggregatedType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SharedType", function() { return _metatypes__WEBPACK_IMPORTED_MODULE_7__["SharedType"]; }); + + + + + + + + + + + +var assign = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].assign, defaults = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].defaults; +function attributes(attrDefs) { + var DefaultModel = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DefaultModel, _super); + function DefaultModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + DefaultModel.attributes = attrDefs; + DefaultModel = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["define"] + ], DefaultModel); + return DefaultModel; + }(_model__WEBPACK_IMPORTED_MODULE_5__["Model"])); + return DefaultModel; +} +_model__WEBPACK_IMPORTED_MODULE_5__["Model"].onExtend = function (BaseClass) { + _transactions__WEBPACK_IMPORTED_MODULE_2__["Transactional"].onExtend.call(this, BaseClass); + var Class = this; + var DefaultCollection = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DefaultCollection, _super); + function DefaultCollection() { + return _super !== null && _super.apply(this, arguments) || this; + } + DefaultCollection.model = Class; + DefaultCollection = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["predefine"] + ], DefaultCollection); + return DefaultCollection; + }(BaseClass.Collection)); + this.DefaultCollection = DefaultCollection; + if (Class.Collection === BaseClass.Collection) { + this.Collection = DefaultCollection; + } +}; +_model__WEBPACK_IMPORTED_MODULE_5__["Model"].onDefine = function (definition, BaseClass) { + var baseProto = BaseClass.prototype; + var _a = Object(_mixin__WEBPACK_IMPORTED_MODULE_4__["createAttributesMixin"])(this.attributes = getAttributes(definition), baseProto._attributes), properties = _a.properties, _localEvents = _a._localEvents, dynamicMixin = tslib__WEBPACK_IMPORTED_MODULE_0__["__rest"](_a, ["properties", "_localEvents"]); + assign(this.prototype, dynamicMixin); + definition.properties = defaults(definition.properties || {}, properties); + definition._localEvents = _localEvents; + _transactions__WEBPACK_IMPORTED_MODULE_2__["Transactional"].onDefine.call(this, definition, BaseClass); + this.DefaultCollection.define(definition.collection || {}); + this.Collection = definition.Collection; + this.Collection.prototype.model = this; + if (definition.endpoint) + this.Collection.prototype._endpoint = definition.endpoint; + Object(_linked_attrs__WEBPACK_IMPORTED_MODULE_6__["addAttributeLinks"])(this); +}; +function getAttributes(_a) { + var defaults = _a.defaults, attributes = _a.attributes, idAttribute = _a.idAttribute; + var definition = attributes || defaults || {}; + if (idAttribute && !(idAttribute in definition)) { + definition[idAttribute] = void 0; + } + return definition; +} +function auto(proto, attrName) { + if (typeof Reflect !== 'undefined' && Reflect.getMetadata) { + if (attrName) { + Object(_attrDef__WEBPACK_IMPORTED_MODULE_3__["type"])(Reflect.getMetadata("design:type", proto, attrName)).as(proto, attrName); + } + else { + var value_1 = proto; + return function (proto, attrName) { + Object(_attrDef__WEBPACK_IMPORTED_MODULE_3__["type"])(Reflect.getMetadata("design:type", proto, attrName)).value(value_1).as(proto, attrName); + }; + } + } + else { + proto._log('error', 'Type-R:MissingImport', 'Add import "reflect-metadata"; as the first line of your app.'); + } +} + + +/***/ }), + +/***/ "../../models/lib/model/io-mixin.js": +/*!*******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/io-mixin.js ***! + \*******************************************************************/ +/*! exports provided: IOModelMixin */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IOModelMixin", function() { return IOModelMixin; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _io_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../io-tools */ "../../models/lib/io-tools.js"); + + +var IOModelMixin = { + save: function (options) { + var _this = this; + if (options === void 0) { options = {}; } + var endpoint = this.getEndpoint(), json = this.toJSON(tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ ioMethod: 'save' }, options)); + return Object(_io_tools__WEBPACK_IMPORTED_MODULE_1__["startIO"])(this, this.isNew() ? + endpoint.create(json, options, this) : + endpoint.update(this.id, json, options, this), options, function (update) { + _this.set(update, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ parse: true, ioMethod: 'save' }, options)); + }); + }, + fetch: function (options) { + var _this = this; + if (options === void 0) { options = {}; } + return Object(_io_tools__WEBPACK_IMPORTED_MODULE_1__["startIO"])(this, this.getEndpoint().read(this.id, options, this), options, function (json) { return _this.set(json, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ parse: true, ioMethod: 'fetch' }, options)); }); + }, + destroy: function (options) { + var _this = this; + if (options === void 0) { options = {}; } + return Object(_io_tools__WEBPACK_IMPORTED_MODULE_1__["startIO"])(this, this.getEndpoint().destroy(this.id, options, this), options, function () { + var collection = _this.collection; + if (collection) { + collection.remove(_this, options); + } + else { + _this.dispose(); + } + return _this; + }); + } +}; + + +/***/ }), + +/***/ "../../models/lib/model/linked-attrs.js": +/*!***********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/linked-attrs.js ***! + \***********************************************************************/ +/*! exports provided: addAttributeLinks, ModelAttrRef */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addAttributeLinks", function() { return addAttributeLinks; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModelAttrRef", function() { return ModelAttrRef; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); + + +function addAttributeLinks(Class) { + var prototype = Class.prototype; + var _attributesArray = prototype._attributesArray; + var AttributeRefs = new Function('model', "\n this._model = model;\n " + _attributesArray.map(function (_a) { + var name = _a.name; + return "this.$" + name + " = void 0; "; + }).join('\n') + "\n "); + AttributeRefs.prototype.__ModelAttrRef = ModelAttrRef; + for (var _i = 0, _attributesArray_1 = _attributesArray; _i < _attributesArray_1.length; _i++) { + var attr = _attributesArray_1[_i]; + var name_1 = attr.name; + Object.defineProperty(AttributeRefs.prototype, name_1, { + get: new Function("\n var x = this.$" + name_1 + ";\n return x && x.value === this._model." + name_1 + " ?\n x :\n ( this.$" + name_1 + " = new this.__ModelAttrRef( this._model, '" + name_1 + "' ) );\n ") + }); + } + prototype.__Attributes$ = AttributeRefs; +} +var ModelAttrRef = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ModelAttrRef, _super); + function ModelAttrRef(model, attr) { + var _this = _super.call(this, model[attr]) || this; + _this.model = model; + _this.attr = attr; + return _this; + } + ModelAttrRef.prototype.set = function (x) { + this.model[this.attr] = x; + }; + Object.defineProperty(ModelAttrRef.prototype, "error", { + get: function () { + return this._error || (this._error = this.model.getValidationError(this.attr)); + }, + set: function (x) { + this._error = x; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(ModelAttrRef.prototype, "descriptor", { + get: function () { + return this.model._attributes[this.attr]; + }, + enumerable: true, + configurable: true + }); + return ModelAttrRef; +}(_linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"])); + + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/any.js": +/*!************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/any.js ***! + \************************************************************************/ +/*! exports provided: AnyType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AnyType", function() { return AnyType; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _updates__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../updates */ "../../models/lib/model/updates.js"); + + + +var notEqual = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].notEqual, assign = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].assign; +var emptyOptions = {}; +var AnyType = (function () { + function AnyType(name, a_options) { + this.name = name; + this.getHook = null; + this.options = a_options; + var options = tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ getHooks: [], transforms: [], changeHandlers: [] }, a_options); + options.getHooks = options.getHooks.slice(); + options.transforms = options.transforms.slice(); + options.changeHandlers = options.changeHandlers.slice(); + var value = options.value, type = options.type, parse = options.parse, toJSON = options.toJSON, changeEvents = options.changeEvents, validate = options.validate, getHooks = options.getHooks, transforms = options.transforms, changeHandlers = options.changeHandlers; + this.value = value; + this.type = type; + if (!options.hasCustomDefault && type) { + this.defaultValue = this.create; + } + else if (_type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].isValidJSON(value)) { + this.defaultValue = new Function("return " + JSON.stringify(value) + ";"); + } + else { + this.defaultValue = this.defaultValue; + } + this.propagateChanges = changeEvents !== false; + this.toJSON = toJSON === void 0 ? this.toJSON : toJSON; + this.validate = validate || this.validate; + if (options.isRequired) { + this.validate = wrapIsRequired(this.validate); + } + transforms.unshift(this.convert); + if (this.get) + getHooks.unshift(this.get); + this.initialize.call(this, options); + if (getHooks.length) { + var getHook_1 = this.getHook = getHooks.reduce(chainGetHooks); + var validate_1 = this.validate; + this.validate = function (record, value, key) { + return validate_1.call(this, record, getHook_1.call(record, value, key), key); + }; + } + this.transform = transforms.length ? transforms.reduce(chainTransforms) : this.transform; + this.handleChange = changeHandlers.length ? changeHandlers.reduce(chainChangeHandlers) : this.handleChange; + var _a = this, doInit = _a.doInit, doUpdate = _a.doUpdate; + this.doInit = parse ? function (value, record, options) { + return doInit.call(this, options.parse && value !== void 0 ? parse.call(record, value, this.name) : value, record, options); + } : doInit; + this.doUpdate = parse ? function (value, record, options, nested) { + return doUpdate.call(this, options.parse && value !== void 0 ? parse.call(record, value, this.name) : value, record, options, nested); + } : doUpdate; + } + AnyType.prototype.canBeUpdated = function (prev, next, options) { }; + AnyType.prototype.transform = function (next, prev, model, options) { return next; }; + AnyType.prototype.convert = function (next, prev, model, options) { return next; }; + AnyType.prototype.isChanged = function (a, b) { + return notEqual(a, b); + }; + AnyType.prototype.handleChange = function (next, prev, model, options) { }; + AnyType.prototype.create = function () { return void 0; }; + AnyType.prototype.clone = function (value, record) { + return value; + }; + AnyType.prototype.dispose = function (record, value) { + this.handleChange(void 0, value, record, emptyOptions); + }; + AnyType.prototype.validate = function (record, value, key) { }; + AnyType.prototype.toJSON = function (value, key, options) { + return value && value.toJSON ? value.toJSON(options) : value; + }; + AnyType.prototype.createPropertyDescriptor = function () { + var _a = this, name = _a.name, getHook = _a.getHook; + if (name !== 'id') { + return { + set: function (value) { + Object(_updates__WEBPACK_IMPORTED_MODULE_2__["setAttribute"])(this, name, value); + }, + get: (getHook ? + function () { + return getHook.call(this, this.attributes[name], name); + } : + function () { return this.attributes[name]; }), + configurable: true + }; + } + }; + AnyType.prototype.initialize = function (name, options) { }; + AnyType.prototype.doInit = function (value, record, options) { + var v = value === void 0 ? this.defaultValue() : value, x = this.transform(v, void 0, record, options); + this.handleChange(x, void 0, record, options); + return x; + }; + AnyType.prototype.doUpdate = function (value, record, options, nested) { + var name = this.name, attributes = record.attributes, prev = attributes[name]; + var next = this.transform(value, prev, record, options); + attributes[name] = next; + if (this.isChanged(next, prev)) { + this.handleChange(next, prev, record, options); + return true; + } + return false; + }; + AnyType.prototype._log = function (level, code, text, value, record, logger) { + record._log(level, code, record.getClassName() + "." + this.name + " " + text, { + 'New value': value, + 'Prev. value': record.attributes[this.name] + }, logger); + }; + AnyType.prototype.defaultValue = function () { + return this.value; + }; + return AnyType; +}()); + +function chainGetHooks(prevHook, nextHook) { + return function (value, name) { + return nextHook.call(this, prevHook.call(this, value, name), name); + }; +} +function chainTransforms(prevTransform, nextTransform) { + return function (next, prev, record, options) { + return nextTransform.call(this, prevTransform.call(this, next, prev, record, options), prev, record, options); + }; +} +function chainChangeHandlers(prevHandler, nextHandler) { + return function (next, prev, record, options) { + prevHandler.call(this, next, prev, record, options); + nextHandler.call(this, next, prev, record, options); + }; +} +function wrapIsRequired(validate) { + return function (record, value, key) { + return value ? validate.call(this, record, value, key) : 'Required'; + }; +} + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/basic.js": +/*!**************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/basic.js ***! + \**************************************************************************/ +/*! exports provided: ImmutableClassType, PrimitiveType, NumericType, ArrayType, ObjectType, doNothing, FunctionType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImmutableClassType", function() { return ImmutableClassType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrimitiveType", function() { return PrimitiveType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NumericType", function() { return NumericType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayType", function() { return ArrayType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ObjectType", function() { return ObjectType; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "doNothing", function() { return doNothing; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FunctionType", function() { return FunctionType; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _any__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./any */ "../../models/lib/model/metatypes/any.js"); + + +var ImmutableClassType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ImmutableClassType, _super); + function ImmutableClassType() { + return _super !== null && _super.apply(this, arguments) || this; + } + ImmutableClassType.prototype.create = function () { + return new this.type(); + }; + ImmutableClassType.prototype.convert = function (next) { + return next == null || next instanceof this.type ? next : new this.type(next); + }; + ImmutableClassType.prototype.toJSON = function (value, key, options) { + return value && value.toJSON ? value.toJSON(options) : value; + }; + ImmutableClassType.prototype.clone = function (value) { + return new this.type(this.toJSON(value)); + }; + ImmutableClassType.prototype.isChanged = function (a, b) { + return a !== b; + }; + return ImmutableClassType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + +var PrimitiveType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](PrimitiveType, _super); + function PrimitiveType() { + return _super !== null && _super.apply(this, arguments) || this; + } + PrimitiveType.prototype.dispose = function () { }; + PrimitiveType.prototype.create = function () { return this.type(); }; + PrimitiveType.prototype.toJSON = function (value) { return value; }; + PrimitiveType.prototype.convert = function (next) { return next == null ? next : this.type(next); }; + PrimitiveType.prototype.isChanged = function (a, b) { return a !== b; }; + PrimitiveType.prototype.clone = function (value) { return value; }; + PrimitiveType.prototype.doInit = function (value, record, options) { + return this.transform(value === void 0 ? this.value : value, void 0, record, options); + }; + PrimitiveType.prototype.doUpdate = function (value, record, options, nested) { + var name = this.name, attributes = record.attributes, prev = attributes[name]; + return prev !== (attributes[name] = this.transform(value, prev, record, options)); + }; + PrimitiveType.prototype.initialize = function () { + if (!this.options.hasCustomDefault) { + this.value = this.type(); + } + }; + return PrimitiveType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + +var NumericType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](NumericType, _super); + function NumericType() { + return _super !== null && _super.apply(this, arguments) || this; + } + NumericType.prototype.create = function () { + return 0; + }; + NumericType.prototype.convert = function (next, prev, record, options) { + var num = next == null ? next : this.type(next); + if (num !== num) { + this._log('error', 'Type-R:InvalidNumber', 'Number attribute is assigned with an invalid number', next, record, options.logger); + } + return num; + }; + NumericType.prototype.validate = function (model, value, name) { + if (value != null && !isFinite(value)) { + return name + ' is not valid number'; + } + }; + return NumericType; +}(PrimitiveType)); + +var ArrayType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ArrayType, _super); + function ArrayType() { + return _super !== null && _super.apply(this, arguments) || this; + } + ArrayType.prototype.toJSON = function (value) { return value; }; + ArrayType.prototype.dispose = function () { }; + ArrayType.prototype.create = function () { return []; }; + ArrayType.prototype.convert = function (next, prev, record, options) { + if (next == null || Array.isArray(next)) + return next; + this._log('error', 'Type-R:InvalidArray', 'Array attribute assigned with non-array value', next, record, options.logger); + return []; + }; + ArrayType.prototype.clone = function (value) { + return value && value.slice(); + }; + return ArrayType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + +var ObjectType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ObjectType, _super); + function ObjectType() { + return _super !== null && _super.apply(this, arguments) || this; + } + ObjectType.prototype.create = function () { return {}; }; + ObjectType.prototype.convert = function (next, prev, record, options) { + if (next == null || typeof next === 'object') + return next; + this._log('error', 'Type-R:InvalidObject', 'Object attribute is assigned with non-object value', next, record, options.logger); + return {}; + }; + return ObjectType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + +function doNothing() { } +var FunctionType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](FunctionType, _super); + function FunctionType() { + return _super !== null && _super.apply(this, arguments) || this; + } + FunctionType.prototype.toJSON = function (value) { return void 0; }; + FunctionType.prototype.create = function () { return doNothing; }; + FunctionType.prototype.dispose = function () { }; + FunctionType.prototype.convert = function (next, prev, record, options) { + if (next == null || typeof next === 'function') + return next; + this._log('error', 'Type-R:InvalidFunction', 'Function attribute assigned with non-function value', next, record, options.logger); + return doNothing; + }; + FunctionType.prototype.clone = function (value) { return value; }; + return FunctionType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/date.js": +/*!*************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/date.js ***! + \*************************************************************************/ +/*! exports provided: DateType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DateType", function() { return DateType; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _any__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./any */ "../../models/lib/model/metatypes/any.js"); + + +var DateType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DateType, _super); + function DateType() { + return _super !== null && _super.apply(this, arguments) || this; + } + DateType.prototype.create = function () { + return new Date(); + }; + DateType.prototype.convert = function (next, a, record, options) { + if (next == null || next instanceof Date) + return next; + var date = new Date(next), timestamp = date.getTime(); + if (timestamp !== timestamp) { + this._log('error', 'Type-R:InvalidDate', 'Date attribute assigned with invalid date', next, record, options.logger); + } + return date; + }; + DateType.prototype.validate = function (model, value, name) { + if (value != null) { + var timestamp = value.getTime(); + if (timestamp !== timestamp) + return name + ' is Invalid Date'; + } + }; + DateType.prototype.toJSON = function (value) { return value && value.toISOString(); }; + DateType.prototype.isChanged = function (a, b) { return (a && a.getTime()) !== (b && b.getTime()); }; + DateType.prototype.doInit = function (value, record, options) { + return this.transform(value === void 0 ? this.defaultValue() : value, void 0, record, options); + }; + DateType.prototype.doUpdate = function (value, record, options, nested) { + var name = this.name, attributes = record.attributes, prev = attributes[name]; + return this.isChanged(prev, attributes[name] = this.transform(value, prev, record, options)); + }; + DateType.prototype.clone = function (value) { return value && new Date(value.getTime()); }; + DateType.prototype.dispose = function () { }; + return DateType; +}(_any__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); + +function supportsDate(date) { + return !isNaN((new Date(date)).getTime()); +} +if (!supportsDate('2011-11-29T15:52:30.5') || + !supportsDate('2011-11-29T15:52:30.52') || + !supportsDate('2011-11-29T15:52:18.867') || + !supportsDate('2011-11-29T15:52:18.867Z') || + !supportsDate('2011-11-29T15:52:18.867-03:30')) { + DateType.prototype.convert = function (value) { + return value == null || value instanceof Date ? value : new Date(safeParseDate(value)); + }; +} +var numericKeys = [1, 4, 5, 6, 7, 10, 11], isoDatePattern = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/; +function safeParseDate(date) { + var timestamp, struct, minutesOffset = 0; + if ((struct = isoDatePattern.exec(date))) { + for (var i = 0, k; (k = numericKeys[i]); ++i) { + struct[k] = +struct[k] || 0; + } + struct[2] = (+struct[2] || 1) - 1; + struct[3] = +struct[3] || 1; + if (struct[8] !== 'Z' && struct[9] !== undefined) { + minutesOffset = struct[10] * 60 + struct[11]; + if (struct[9] === '+') { + minutesOffset = 0 - minutesOffset; + } + } + timestamp = + Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); + } + else { + timestamp = Date.parse(date); + } + return timestamp; +} + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/index.js": +/*!**************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/index.js ***! + \**************************************************************************/ +/*! exports provided: getMetatype, AnyType, ImmutableClassType, PrimitiveType, NumericType, ArrayType, ObjectType, doNothing, FunctionType, DateType, AggregatedType, SharedType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMetatype", function() { return getMetatype; }); +/* harmony import */ var _basic__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./basic */ "../../models/lib/model/metatypes/basic.js"); +/* harmony import */ var _date__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./date */ "../../models/lib/model/metatypes/date.js"); +/* harmony import */ var _any__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./any */ "../../models/lib/model/metatypes/any.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AnyType", function() { return _any__WEBPACK_IMPORTED_MODULE_2__["AnyType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ImmutableClassType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["ImmutableClassType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PrimitiveType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["PrimitiveType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "NumericType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["NumericType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ArrayType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["ArrayType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ObjectType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["ObjectType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "doNothing", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["doNothing"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FunctionType", function() { return _basic__WEBPACK_IMPORTED_MODULE_0__["FunctionType"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DateType", function() { return _date__WEBPACK_IMPORTED_MODULE_1__["DateType"]; }); + +/* harmony import */ var _owned__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./owned */ "../../models/lib/model/metatypes/owned.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "AggregatedType", function() { return _owned__WEBPACK_IMPORTED_MODULE_3__["AggregatedType"]; }); + +/* harmony import */ var _shared__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./shared */ "../../models/lib/model/metatypes/shared.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SharedType", function() { return _shared__WEBPACK_IMPORTED_MODULE_4__["SharedType"]; }); + + + + + + + + + +var builtins = [String, Number, Boolean, Date, Object, Array, Function], metatypes = [_basic__WEBPACK_IMPORTED_MODULE_0__["PrimitiveType"], _basic__WEBPACK_IMPORTED_MODULE_0__["NumericType"], _basic__WEBPACK_IMPORTED_MODULE_0__["PrimitiveType"], _date__WEBPACK_IMPORTED_MODULE_1__["DateType"], _basic__WEBPACK_IMPORTED_MODULE_0__["ObjectType"], _basic__WEBPACK_IMPORTED_MODULE_0__["ArrayType"], _basic__WEBPACK_IMPORTED_MODULE_0__["FunctionType"]]; +function getMetatype(Ctor) { + return Ctor._metatype || resolveBuiltins(Ctor); +} +_any__WEBPACK_IMPORTED_MODULE_2__["AnyType"].create = function (options, name) { + var type = options.type, AttributeCtor = options._metatype || (type ? getMetatype(type) : _any__WEBPACK_IMPORTED_MODULE_2__["AnyType"]); + return new AttributeCtor(name, options); +}; +function resolveBuiltins(Ctor) { + var idx = builtins.indexOf(Ctor); + return idx < 0 ? _basic__WEBPACK_IMPORTED_MODULE_0__["ImmutableClassType"] : metatypes[idx]; +} + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/owned.js": +/*!**************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/owned.js ***! + \**************************************************************************/ +/*! exports provided: AggregatedType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AggregatedType", function() { return AggregatedType; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _any__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./any */ "../../models/lib/model/metatypes/any.js"); + + + +var free = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].free, aquire = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].aquire; +var AggregatedType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](AggregatedType, _super); + function AggregatedType() { + return _super !== null && _super.apply(this, arguments) || this; + } + AggregatedType.prototype.clone = function (value) { + return value ? value.clone() : value; + }; + AggregatedType.prototype.toJSON = function (x, key, options) { return x && x.toJSON(options); }; + AggregatedType.prototype.doInit = function (value, record, options) { + var v = options.clone ? this.clone(value) : (value === void 0 ? this.defaultValue() : value); + var x = this.transform(v, void 0, record, options); + this.handleChange(x, void 0, record, options); + return x; + }; + AggregatedType.prototype.doUpdate = function (value, record, options, nested) { + var key = this.name, attributes = record.attributes; + var prev = attributes[key]; + var update; + if (update = this.canBeUpdated(prev, value, options)) { + var nestedTransaction = prev._createTransaction(update, options); + if (nestedTransaction) { + if (nested) { + nested.push(nestedTransaction); + } + else { + nestedTransaction.commit(record); + } + if (this.propagateChanges) + return true; + } + return false; + } + var next = this.transform(value, prev, record, options); + attributes[key] = next; + if (this.isChanged(next, prev)) { + this.handleChange(next, prev, record, options); + return true; + } + return false; + }; + AggregatedType.prototype.canBeUpdated = function (prev, next, options) { + if (prev && next != null) { + if (next instanceof this.type) { + if (options.merge) + return next.__inner_state__; + } + else { + return next; + } + } + }; + AggregatedType.prototype.convert = function (next, prev, record, options) { + if (next == null) + return next; + if (next instanceof this.type) { + if (next._shared && !(next._shared & _transactions__WEBPACK_IMPORTED_MODULE_1__["ItemsBehavior"].persistent)) { + this._log('error', 'Type-R:InvalidCollection', 'aggregated collection attribute is assigned with shared collection type', next, record, options.logger); + } + if (options.merge) + return next.clone(); + if (next._owner) { + this._log('warn', 'Type-R:InvalidOwner', 'object alreay has an owner and was cloned. Use explicit object.clone() to dismiss this warning.', next, record, options.logger); + return next.clone(); + } + return next; + } + return this.type.create(next, options); + }; + AggregatedType.prototype.dispose = function (record, value) { + if (value) { + this.handleChange(void 0, value, record, {}); + } + }; + AggregatedType.prototype.validate = function (record, value) { + var error = value && value.validationError; + if (error) + return error; + }; + AggregatedType.prototype.create = function () { + return this.type.create(); + }; + AggregatedType.prototype.initialize = function (options) { + options.changeHandlers.unshift(this._handleChange); + }; + AggregatedType.prototype._handleChange = function (next, prev, record, options) { + if (prev) { + free(record, prev); + options.unset || prev.dispose(); + } + if (next) + aquire(record, next, this.name); + }; + return AggregatedType; +}(_any__WEBPACK_IMPORTED_MODULE_2__["AnyType"])); + + + +/***/ }), + +/***/ "../../models/lib/model/metatypes/shared.js": +/*!***************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/metatypes/shared.js ***! + \***************************************************************************/ +/*! exports provided: SharedType */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SharedType", function() { return SharedType; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _any__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./any */ "../../models/lib/model/metatypes/any.js"); + + + + +var on = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["eventsApi"].on, off = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["eventsApi"].off, free = _transactions__WEBPACK_IMPORTED_MODULE_2__["transactionApi"].free, aquire = _transactions__WEBPACK_IMPORTED_MODULE_2__["transactionApi"].aquire; +var shareAndListen = _transactions__WEBPACK_IMPORTED_MODULE_2__["ItemsBehavior"].listen | _transactions__WEBPACK_IMPORTED_MODULE_2__["ItemsBehavior"].share; +var SharedType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SharedType, _super); + function SharedType() { + return _super !== null && _super.apply(this, arguments) || this; + } + SharedType.prototype.doInit = function (value, record, options) { + var v = options.clone ? this.clone(value, record) : (value === void 0 ? this.defaultValue() : value); + var x = this.transform(v, void 0, record, options); + this.handleChange(x, void 0, record, options); + return x; + }; + SharedType.prototype.doUpdate = function (value, record, options, nested) { + var key = this.name, attributes = record.attributes; + var prev = attributes[key]; + var update; + if (update = this.canBeUpdated(prev, value, options)) { + var nestedTransaction = prev._createTransaction(update, options); + if (nestedTransaction) { + if (nested) { + nested.push(nestedTransaction); + } + else { + nestedTransaction.commit(record); + } + if (this.propagateChanges) + return true; + } + return false; + } + var next = this.transform(value, prev, record, options); + attributes[key] = next; + if (this.isChanged(next, prev)) { + this.handleChange(next, prev, record, options); + return true; + } + return false; + }; + SharedType.prototype.clone = function (value, record) { + if (!value || value._owner !== record) + return value; + var clone = value.clone(); + aquire(record, clone, this.name); + return clone; + }; + SharedType.prototype.toJSON = function () { }; + SharedType.prototype.canBeUpdated = function (prev, next, options) { + if (prev && next != null && !(next instanceof this.type)) { + return next; + } + }; + SharedType.prototype.convert = function (next, prev, record, options) { + if (next == null || next instanceof this.type) + return next; + var implicitObject = new this.type(next, options, shareAndListen); + aquire(record, implicitObject, this.name); + return implicitObject; + }; + SharedType.prototype.validate = function (model, value, name) { }; + SharedType.prototype.create = function () { + return null; + }; + SharedType.prototype._handleChange = function (next, prev, record, options) { + if (prev) { + if (prev._owner === record) { + free(record, prev); + options.unset || prev.dispose(); + } + else { + off(prev, prev._changeEventName, this._onChange, record); + } + } + if (next) { + if (next._owner !== record) { + on(next, next._changeEventName, this._onChange, record); + } + } + }; + SharedType.prototype.dispose = function (record, value) { + if (value) { + this.handleChange(void 0, value, record, {}); + } + }; + SharedType.prototype.initialize = function (options) { + var attribute = this; + this._onChange = this.propagateChanges ? function (child, options, initiator) { + this === initiator || this.forceAttributeChange(attribute.name, options); + } : ignore; + options.changeHandlers.unshift(this._handleChange); + }; + return SharedType; +}(_any__WEBPACK_IMPORTED_MODULE_3__["AnyType"])); + +function ignore() { } + + +/***/ }), + +/***/ "../../models/lib/model/mixin.js": +/*!****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/mixin.js ***! + \****************************************************************/ +/*! exports provided: createAttribute, createAttributesMixin */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createAttribute", function() { return createAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createAttributesMixin", function() { return createAttributesMixin; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _traversable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../traversable */ "../../models/lib/traversable.js"); +/* harmony import */ var _attrDef__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attrDef */ "../../models/lib/model/attrDef.js"); +/* harmony import */ var _metatypes__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./metatypes */ "../../models/lib/model/metatypes/index.js"); +/* harmony import */ var _updates__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./updates */ "../../models/lib/model/updates.js"); + + + + + + +function createAttribute(spec, name) { + return _metatypes__WEBPACK_IMPORTED_MODULE_4__["AnyType"].create(_attrDef__WEBPACK_IMPORTED_MODULE_3__["ChainableAttributeSpec"].from(spec).options, name); +} +function createAttributesMixin(attributesDefinition, baseClassAttributes) { + var myAttributes = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].transform({}, attributesDefinition, createAttribute), allAttributes = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].defaults({}, myAttributes, baseClassAttributes); + var ConstructorsMixin = Object(_updates__WEBPACK_IMPORTED_MODULE_5__["constructorsMixin"])(allAttributes); + return tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({}, ConstructorsMixin, { _attributes: new ConstructorsMixin.AttributesCopy(allAttributes), _attributesArray: Object.keys(allAttributes).map(function (key) { return allAttributes[key]; }), properties: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].transform({}, myAttributes, function (x) { return x.createPropertyDescriptor(); }) }, localEventsMixin(myAttributes), { _endpoints: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].transform({}, allAttributes, function (attrDef) { return attrDef.options.endpoint; }) }); +} +function localEventsMixin(attrSpecs) { + var _localEvents; + for (var key in attrSpecs) { + var attribute = attrSpecs[key], _onChange = attribute.options._onChange; + if (_onChange) { + _localEvents || (_localEvents = new _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["eventsApi"].EventMap()); + _localEvents.addEvent('change:' + key, typeof _onChange === 'string' ? + createWatcherFromRef(_onChange, key) : + wrapWatcher(_onChange, key)); + } + } + return _localEvents ? { _localEvents: _localEvents } : {}; +} +function wrapWatcher(watcher, key) { + return function (record, value) { + watcher.call(record, value, key); + }; +} +function createWatcherFromRef(ref, key) { + var _a = new _traversable__WEBPACK_IMPORTED_MODULE_2__["CompiledReference"](ref, true), local = _a.local, resolve = _a.resolve, tail = _a.tail; + return local ? + function (record, value) { + record[tail](value, key); + } : + function (record, value) { + resolve(record)[tail](value, key); + }; +} + + +/***/ }), + +/***/ "../../models/lib/model/model.js": +/*!****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/model.js ***! + \****************************************************************/ +/*! exports provided: Model, ModelEntriesIterator */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Model", function() { return Model; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModelEntriesIterator", function() { return ModelEntriesIterator; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _attrDef__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attrDef */ "../../models/lib/model/attrDef.js"); +/* harmony import */ var _io_mixin__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./io-mixin */ "../../models/lib/model/io-mixin.js"); +/* harmony import */ var _metatypes__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./metatypes */ "../../models/lib/model/metatypes/index.js"); +/* harmony import */ var _updates__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./updates */ "../../models/lib/model/updates.js"); + + + + + + + +var assign = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].assign, isEmpty = _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].isEmpty; +var _cidCounter = 0; +var Model = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](Model, _super); + function Model(a_values, a_options) { + var _this = _super.call(this, _cidCounter++) || this; + _this._attributes$ = void 0; + _this.attributes = {}; + var options = a_options || {}, values = (options.parse ? _this.parse(a_values, options) : a_values) || {}; + _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["isProduction"] || typeCheck(_this, values, options); + _this._previousAttributes = _this.attributes = new _this.Attributes(_this, values, options); + _this.initialize(a_values, a_options); + if (_this._localEvents) + _this._localEvents.subscribe(_this, _this); + return _this; + } + Model_1 = Model; + Model.onDefine = function (definition, BaseClass) { }; + Object.defineProperty(Model, "ref", { + get: function () { + var _this = this; + return Object(_attrDef__WEBPACK_IMPORTED_MODULE_3__["type"])(this) + .toJSON(function (x) { return x ? x.id : null; }) + .parse(function (x) { + var _a; + return _a = {}, _a[_this.prototype.idAttribute] = x, _a; + }); + }, + enumerable: true, + configurable: true + }); + Model.extendAttrs = function (attrs) { + return this.defaults(attrs); + }; + Model.defaults = function (attrs) { + return this.extend({ attributes: attrs }); + }; + Object.defineProperty(Model.prototype, "$", { + get: function () { + return this._attributes$ || (this._attributes$ = new this.__Attributes$(this)); + }, + enumerable: true, + configurable: true + }); + Model.prototype.previousAttributes = function () { return new this.AttributesCopy(this._previousAttributes); }; + Object.defineProperty(Model.prototype, "__inner_state__", { + get: function () { return this.attributes; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Model.prototype, "changed", { + get: function () { + var changed = this._changedAttributes; + if (!changed) { + var prev = this._previousAttributes; + changed = {}; + var attributes = this.attributes; + for (var _i = 0, _a = this._attributesArray; _i < _a.length; _i++) { + var attr = _a[_i]; + var key = attr.name, value = attributes[key]; + if (attr.isChanged(value, prev[key])) { + changed[key] = value; + } + } + this._changedAttributes = changed; + } + return changed; + }, + enumerable: true, + configurable: true + }); + Model.prototype.changedAttributes = function (diff) { + if (!diff) + return this.hasChanged() ? tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({}, this.changed) : false; + var val, changed = false, old = this._transaction ? this._previousAttributes : this.attributes, attrSpecs = this._attributes; + for (var attr in diff) { + if (!attrSpecs[attr].isChanged(old[attr], (val = diff[attr]))) + continue; + (changed || (changed = {}))[attr] = val; + } + return changed; + }; + Model.prototype.hasChanged = function (key) { + var _previousAttributes = this._previousAttributes; + if (!_previousAttributes) + return false; + return key ? + this._attributes[key].isChanged(this.attributes[key], _previousAttributes[key]) : + !isEmpty(this.changed); + }; + Model.prototype.previous = function (key) { + if (key) { + var _previousAttributes = this._previousAttributes; + if (_previousAttributes) + return _previousAttributes[key]; + } + return null; + }; + Model.prototype.isNew = function () { + return this.id == null; + }; + Model.prototype.has = function (key) { + return this[key] != void 0; + }; + Model.prototype.unset = function (key, options) { + var _a; + var value = this[key]; + this.set((_a = {}, _a[key] = void 0, _a), tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({ unset: true }, options)); + return value; + }; + Model.prototype.clear = function (options) { + var _this = this; + var nullify = options && options.nullify; + this.transaction(function () { + _this.forEach(function (value, key) { return _this[key] = nullify ? null : void 0; }); + }, options); + return this; + }; + Model.prototype.getOwner = function () { + var owner = this._owner; + return this._ownerKey ? owner : owner && owner._owner; + }; + Object.defineProperty(Model.prototype, "id", { + get: function () { return this.attributes[this.idAttribute]; }, + set: function (x) { Object(_updates__WEBPACK_IMPORTED_MODULE_6__["setAttribute"])(this, this.idAttribute, x); }, + enumerable: true, + configurable: true + }); + Model.prototype.defaults = function (values) { + if (values === void 0) { values = {}; } + var defaults = {}, _attributesArray = this._attributesArray; + for (var _i = 0, _attributesArray_1 = _attributesArray; _i < _attributesArray_1.length; _i++) { + var attr = _attributesArray_1[_i]; + var key = attr.name, value = values[key]; + defaults[key] = value === void 0 ? attr.defaultValue() : value; + } + return defaults; + }; + Model.prototype.initialize = function (values, options) { }; + Model.prototype.clone = function (options) { + if (options === void 0) { options = {}; } + var copy = new this.constructor(this.attributes, { clone: true }); + if (options.pinStore) + copy._defaultStore = this.getStore(); + return copy; + }; + Model.prototype._validateNested = function (errors) { + var length = 0; + var attributes = this.attributes; + for (var _i = 0, _a = this._attributesArray; _i < _a.length; _i++) { + var attribute = _a[_i]; + var name_1 = attribute.name, error = attribute.validate(this, attributes[name_1], name_1); + if (error) { + errors[name_1] = error; + length++; + } + } + return length; + }; + Model.prototype.get = function (key) { + return this[key]; + }; + Model.prototype.set = function (values, options) { + if (values) { + var transaction = this._createTransaction(values, options); + transaction && transaction.commit(); + } + return this; + }; + Model.prototype.toJSON = function (options) { + var json = {}, attributes = this.attributes; + for (var _i = 0, _a = this._attributesArray; _i < _a.length; _i++) { + var attribute = _a[_i]; + var name_2 = attribute.name, value = attributes[name_2]; + if (value !== void 0) { + var asJson = attribute.toJSON.call(this, value, name_2, options); + if (asJson !== void 0) + json[name_2] = asJson; + } + } + return json; + }; + Model.prototype.parse = function (data, options) { + return data; + }; + Model.prototype.deepSet = function (name, value, options) { + var _this = this; + this.transaction(function () { + var _a; + var path = name.split('.'), l = path.length - 1, attr = path[l]; + var model = _this; + for (var i = 0; i < l; i++) { + var key = path[i]; + var next = model.get ? model.get(key) : model[key]; + if (!next) { + var attrSpecs = model._attributes; + if (attrSpecs) { + var newModel = attrSpecs[key].create(); + if (options && options.nullify && newModel._attributes) { + newModel.clear(options); + } + model[key] = next = newModel; + } + else + return; + } + model = next; + } + if (model.set) { + model.set((_a = {}, _a[attr] = value, _a), options); + } + else { + model[attr] = value; + } + }); + return this; + }; + Object.defineProperty(Model.prototype, "collection", { + get: function () { + return this._ownerKey ? null : this._owner; + }, + enumerable: true, + configurable: true + }); + Model.prototype.dispose = function () { + if (this._disposed) + return; + var attributes = this.attributes; + for (var _i = 0, _a = this._attributesArray; _i < _a.length; _i++) { + var attr = _a[_i]; + attr.dispose(this, attributes[attr.name]); + } + _super.prototype.dispose.call(this); + }; + Model.prototype._log = function (level, topic, text, props, a_logger) { + (a_logger || _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["logger"]).trigger(level, topic, this.getClassName() + ' ' + text, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({}, props, { 'Model': this, 'Attributes definition': this._attributes })); + }; + Model.prototype.getClassName = function () { + return _super.prototype.getClassName.call(this) || 'Model'; + }; + Model.prototype._createTransaction = function (values, options) { return void 0; }; + Model.prototype.forEach = function (iteratee, context) { + var fun = context !== void 0 ? function (v, k) { return iteratee.call(context, v, k); } : iteratee, attributes = this.attributes; + for (var key in this.attributes) { + var value = attributes[key]; + if (value !== void 0) + fun(value, key); + } + }; + Model.prototype.mapObject = function (a_fun, context) { + var fun = context === void 0 ? a_fun : a_fun.bind(context); + return _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["tools"].transform({}, this.attributes, fun); + }; + Model.prototype[Symbol.iterator] = function () { + return new ModelEntriesIterator(this); + }; + Model.prototype.entries = function () { + return new ModelEntriesIterator(this); + }; + Model.prototype.keys = function () { + var keys = []; + this.forEach(function (value, key) { return keys.push(key); }); + return keys; + }; + var Model_1; + Model._metatype = _metatypes__WEBPACK_IMPORTED_MODULE_5__["AggregatedType"]; + Model.id = Object(_attrDef__WEBPACK_IMPORTED_MODULE_3__["type"])(String).value(null); + Model = Model_1 = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["define"])({ + cidPrefix: 'm', + _changeEventName: 'change', + idAttribute: 'id' + }), + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["definitions"])({ + defaults: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["mixinRules"].merge, + attributes: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["mixinRules"].merge, + collection: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["mixinRules"].merge, + Collection: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["mixinRules"].value, + idAttribute: _type_r_mixture__WEBPACK_IMPORTED_MODULE_1__["mixinRules"].protoValue + }) + ], Model); + return Model; +}(_transactions__WEBPACK_IMPORTED_MODULE_2__["Transactional"])); + +; +assign(Model.prototype, _updates__WEBPACK_IMPORTED_MODULE_6__["UpdateModelMixin"], _io_mixin__WEBPACK_IMPORTED_MODULE_4__["IOModelMixin"]); +var BaseModelAttributes = (function () { + function BaseModelAttributes(record, x, options) { + this.id = x.id; + } + return BaseModelAttributes; +}()); +Model.prototype.Attributes = BaseModelAttributes; +var BaseModelAttributesCopy = (function () { + function BaseModelAttributesCopy(x) { + this.id = x.id; + } + return BaseModelAttributesCopy; +}()); +Model.prototype.AttributesCopy = BaseModelAttributesCopy; +var IdAttribute = _metatypes__WEBPACK_IMPORTED_MODULE_5__["AnyType"].create({ value: void 0 }, 'id'); +Model.prototype._attributes = { id: IdAttribute }; +Model.prototype._attributesArray = [IdAttribute]; +function typeCheck(record, values, options) { + if (Object(_updates__WEBPACK_IMPORTED_MODULE_6__["shouldBeAnObject"])(record, values, options)) { + var _attributes = record._attributes; + var unknown = void 0; + for (var name_3 in values) { + if (!_attributes[name_3]) { + unknown || (unknown = []); + unknown.push("'" + name_3 + "'"); + } + } + if (unknown) { + Object(_updates__WEBPACK_IMPORTED_MODULE_6__["unknownAttrsWarning"])(record, unknown, { values: values }, options); + } + } +} +var ModelEntriesIterator = (function () { + function ModelEntriesIterator(record) { + this.record = record; + this.idx = 0; + } + ModelEntriesIterator.prototype.next = function () { + var record = this.record, metatype = record._attributesArray[this.idx++]; + return { + done: !metatype, + value: metatype ? [metatype.name, record[metatype.name]] : void 0 + }; + }; + return ModelEntriesIterator; +}()); + + + +/***/ }), + +/***/ "../../models/lib/model/updates.js": +/*!******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/model/updates.js ***! + \******************************************************************/ +/*! exports provided: setAttribute, UpdateModelMixin, unknownAttrsWarning, constructorsMixin, shouldBeAnObject, ModelTransaction */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setAttribute", function() { return setAttribute; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UpdateModelMixin", function() { return UpdateModelMixin; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unknownAttrsWarning", function() { return unknownAttrsWarning; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "constructorsMixin", function() { return constructorsMixin; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shouldBeAnObject", function() { return shouldBeAnObject; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModelTransaction", function() { return ModelTransaction; }); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); + + +var _begin = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].begin, _markAsDirty = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].markAsDirty, commit = _transactions__WEBPACK_IMPORTED_MODULE_1__["transactionApi"].commit; +var trigger3 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_0__["eventsApi"].trigger3; +function setAttribute(record, name, value) { + var isRoot = begin(record), options = {}; + if (record._attributes[name].doUpdate(value, record, options)) { + markAsDirty(record, options); + trigger3(record, 'change:' + name, record, record.attributes[name], options); + } + isRoot && commit(record); +} +function begin(record) { + if (_begin(record)) { + record._previousAttributes = new record.AttributesCopy(record.attributes); + record._changedAttributes = null; + return true; + } + return false; +} +function markAsDirty(record, options) { + if (record._changedAttributes) { + record._changedAttributes = null; + } + return _markAsDirty(record, options); +} +var UpdateModelMixin = { + transaction: function (fun, options) { + if (options === void 0) { options = {}; } + var isRoot = begin(this); + fun.call(this, this); + isRoot && commit(this); + }, + _onChildrenChange: function (child, options) { + var _ownerKey = child._ownerKey, attribute = this._attributes[_ownerKey]; + if (!attribute || attribute.propagateChanges) + this.forceAttributeChange(_ownerKey, options); + }, + forceAttributeChange: function (key, options) { + if (options === void 0) { options = {}; } + var isRoot = begin(this); + if (markAsDirty(this, options)) { + trigger3(this, 'change:' + key, this, this.attributes[key], options); + } + isRoot && commit(this); + }, + _createTransaction: function (a_values, options) { + if (options === void 0) { options = {}; } + var isRoot = begin(this), changes = [], nested = [], _attributes = this._attributes, values = options.parse ? this.parse(a_values, options) : a_values; + var unknown; + if (shouldBeAnObject(this, values, options)) { + for (var name_1 in values) { + var spec = _attributes[name_1]; + if (spec) { + if (spec.doUpdate(values[name_1], this, options, nested)) { + changes.push(name_1); + } + } + else { + unknown || (unknown = []); + unknown.push("'" + name_1 + "'"); + } + } + if (unknown) { + unknownAttrsWarning(this, unknown, { values: values }, options); + } + } + if (changes.length && markAsDirty(this, options)) { + return new ModelTransaction(this, isRoot, nested, changes); + } + for (var _i = 0, nested_1 = nested; _i < nested_1.length; _i++) { + var pendingTransaction = nested_1[_i]; + pendingTransaction.commit(this); + } + isRoot && commit(this); + } +}; +function unknownAttrsWarning(record, unknown, props, options) { + record._log('warn', 'Type-R:UnknownAttrs', "undefined attributes " + unknown.join(', ') + " are ignored.", props, options.logger); +} +function constructorsMixin(attrDefs) { + var attrs = Object.keys(attrDefs); + var AttributesCopy = new Function('values', "\n " + attrs.map(function (attr) { return "\n this." + attr + " = values." + attr + ";\n "; }).join('') + "\n "); + AttributesCopy.prototype = Object.prototype; + var Attributes = new Function('record', 'values', 'options', "\n var _attrs = record._attributes;\n\n " + attrs.map(function (attr) { return "\n this." + attr + " = _attrs." + attr + ".doInit( values." + attr + ", record, options );\n "; }).join('') + "\n "); + Attributes.prototype = Object.prototype; + return { Attributes: Attributes, AttributesCopy: AttributesCopy }; +} +function shouldBeAnObject(record, values, options) { + if (values && values.constructor === Object) + return true; + record._log('error', 'Type-R:InvalidObject', 'update with non-object is ignored!', { values: values }, options.logger); + return false; +} +var ModelTransaction = (function () { + function ModelTransaction(object, isRoot, nested, changes) { + this.object = object; + this.isRoot = isRoot; + this.nested = nested; + this.changes = changes; + } + ModelTransaction.prototype.commit = function (initiator) { + var _a = this, nested = _a.nested, object = _a.object, changes = _a.changes; + for (var _i = 0, nested_2 = nested; _i < nested_2.length; _i++) { + var transaction = nested_2[_i]; + transaction.commit(object); + } + var attributes = object.attributes, _isDirty = object._isDirty; + for (var _b = 0, changes_1 = changes; _b < changes_1.length; _b++) { + var key = changes_1[_b]; + trigger3(object, 'change:' + key, object, attributes[key], _isDirty); + } + this.isRoot && commit(object, initiator); + }; + return ModelTransaction; +}()); + + + +/***/ }), + +/***/ "../../models/lib/relations/commons.js": +/*!**********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/relations/commons.js ***! + \**********************************************************************/ +/*! exports provided: parseReference */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parseReference", function() { return parseReference; }); +/* harmony import */ var _traversable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../traversable */ "../../models/lib/traversable.js"); + +function parseReference(collectionRef) { + switch (typeof collectionRef) { + case 'function': + return function (root) { return collectionRef.call(root); }; + case 'object': + return function () { return collectionRef; }; + case 'string': + var resolve = new _traversable__WEBPACK_IMPORTED_MODULE_0__["CompiledReference"](collectionRef).resolve; + return resolve; + } +} + + +/***/ }), + +/***/ "../../models/lib/relations/from.js": +/*!*******************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/relations/from.js ***! + \*******************************************************************/ +/*! exports provided: memberOf */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "memberOf", function() { return theMemberOf; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../model */ "../../models/lib/model/index.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commons */ "../../models/lib/relations/commons.js"); + + + +var ModelRefType = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ModelRefType, _super); + function ModelRefType() { + return _super !== null && _super.apply(this, arguments) || this; + } + ModelRefType.prototype.toJSON = function (value) { + return value && typeof value === 'object' ? value.id : value; + }; + ModelRefType.prototype.clone = function (value) { + return value && typeof value === 'object' ? value.id : value; + }; + ModelRefType.prototype.isChanged = function (a, b) { + var aId = a && (a.id == null ? a : a.id), bId = b && (b.id == null ? b : b.id); + return aId !== bId; + }; + ModelRefType.prototype.validate = function (model, value, name) { }; + return ModelRefType; +}(_model__WEBPACK_IMPORTED_MODULE_1__["AnyType"])); +function theMemberOf(masterCollection, T) { + var getMasterCollection = Object(_commons__WEBPACK_IMPORTED_MODULE_2__["parseReference"])(masterCollection); + var typeSpec = new _model__WEBPACK_IMPORTED_MODULE_1__["ChainableAttributeSpec"]({ + value: null, + _metatype: ModelRefType + }); + return typeSpec + .get(function (objOrId, name) { + if (typeof objOrId === 'object') + return objOrId; + var collection = getMasterCollection(this); + var record = null; + if (collection && collection.length) { + record = collection.get(objOrId) || null; + this.attributes[name] = record; + record && this._attributes[name].handleChange(record, null, this, {}); + } + return record; + }); +} + +_model__WEBPACK_IMPORTED_MODULE_1__["Model"].memberOf = theMemberOf; + + +/***/ }), + +/***/ "../../models/lib/relations/index.js": +/*!********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/relations/index.js ***! + \********************************************************************/ +/*! exports provided: memberOf, subsetOf, Store */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _from__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./from */ "../../models/lib/relations/from.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "memberOf", function() { return _from__WEBPACK_IMPORTED_MODULE_0__["memberOf"]; }); + +/* harmony import */ var _subsetOf__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./subsetOf */ "../../models/lib/relations/subsetOf.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subsetOf", function() { return _subsetOf__WEBPACK_IMPORTED_MODULE_1__["subsetOf"]; }); + +/* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./store */ "../../models/lib/relations/store.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Store", function() { return _store__WEBPACK_IMPORTED_MODULE_2__["Store"]; }); + + + + + + +/***/ }), + +/***/ "../../models/lib/relations/store.js": +/*!********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/relations/store.js ***! + \********************************************************************/ +/*! exports provided: Store */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Store", function() { return Store; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../model */ "../../models/lib/model/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); + + + +var _store = null; +var Store = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](Store, _super); + function Store() { + return _super !== null && _super.apply(this, arguments) || this; + } + Store.prototype.getStore = function () { return this; }; + Store.prototype.get = function (name) { + var local = this[name]; + if (local || this === this._defaultStore) + return local; + return this._owner ? this._owner.get(name) : this._defaultStore.get(name); + }; + Object.defineProperty(Store, "global", { + get: function () { return _store; }, + set: function (store) { + if (_store) { + _store.dispose(); + } + _transactions__WEBPACK_IMPORTED_MODULE_2__["Transactional"].prototype._defaultStore = _store = store; + }, + enumerable: true, + configurable: true + }); + return Store; +}(_model__WEBPACK_IMPORTED_MODULE_1__["Model"])); + +Store.global = new Store(); + + +/***/ }), + +/***/ "../../models/lib/relations/subsetOf.js": +/*!***********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/relations/subsetOf.js ***! + \***********************************************************************/ +/*! exports provided: subsetOf */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subsetOf", function() { return subsetOf; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _collection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../collection */ "../../models/lib/collection/index.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../model */ "../../models/lib/model/index.js"); +/* harmony import */ var _transactions__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../transactions */ "../../models/lib/transactions.js"); +/* harmony import */ var _commons__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./commons */ "../../models/lib/relations/commons.js"); + + + + + + +function subsetOf(masterCollection, T) { + var CollectionClass = T || _collection__WEBPACK_IMPORTED_MODULE_1__["Collection"], SubsetOf = CollectionClass._SubsetOf || (CollectionClass._SubsetOf = defineSubsetCollection(CollectionClass)), getMasterCollection = Object(_commons__WEBPACK_IMPORTED_MODULE_5__["parseReference"])(masterCollection); + return Object(_model__WEBPACK_IMPORTED_MODULE_3__["type"])(SubsetOf).get(function (refs) { + !refs || refs.resolvedWith || refs.resolve(getMasterCollection(this)); + return refs; + }); +} +_collection__WEBPACK_IMPORTED_MODULE_1__["Collection"].subsetOf = subsetOf; +_collection__WEBPACK_IMPORTED_MODULE_1__["Collection"].prototype.createSubset = function (models, options) { + var SubsetOf = subsetOf(this, this.constructor).options.type, subset = new SubsetOf(models, options); + subset.resolve(this); + return subset; +}; +var subsetOfBehavior = _transactions__WEBPACK_IMPORTED_MODULE_4__["ItemsBehavior"].share | _transactions__WEBPACK_IMPORTED_MODULE_4__["ItemsBehavior"].persistent; +function defineSubsetCollection(CollectionClass) { + var SubsetOfCollection = (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubsetOfCollection, _super); + function SubsetOfCollection(recordsOrIds, options) { + var _this = _super.call(this, [], options, subsetOfBehavior) || this; + _this.resolvedWith = null; + _this.refs = toArray(recordsOrIds); + return _this; + } + Object.defineProperty(SubsetOfCollection.prototype, "__inner_state__", { + get: function () { return this.refs || this.models; }, + enumerable: true, + configurable: true + }); + SubsetOfCollection.prototype.add = function (a_elements, options) { + if (options === void 0) { options = {}; } + var resolvedWith = this.resolvedWith, toAdd = toArray(a_elements); + if (resolvedWith) { + return _super.prototype.add.call(this, resolveRefs(resolvedWith, toAdd), options); + } + else { + if (toAdd.length) { + var isRoot = _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].begin(this); + this.refs = this.refs ? this.refs.concat(toAdd) : toAdd.slice(); + _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].markAsDirty(this, options); + isRoot && _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].commit(this); + } + } + }; + SubsetOfCollection.prototype.reset = function (a_elements, options) { + if (options === void 0) { options = {}; } + var resolvedWith = this.resolvedWith, elements = toArray(a_elements); + return resolvedWith ? + _super.prototype.reset.call(this, resolveRefs(resolvedWith, elements), options) : + delaySet(this, elements, options) || []; + }; + SubsetOfCollection.prototype._createTransaction = function (a_elements, options) { + var resolvedWith = this.resolvedWith, elements = toArray(a_elements); + return resolvedWith ? + _super.prototype._createTransaction.call(this, resolveRefs(resolvedWith, elements), options) : + delaySet(this, elements, options); + }; + SubsetOfCollection.prototype.toJSON = function () { + return this.refs ? + this.refs.map(function (objOrId) { return objOrId.id || objOrId; }) : + this.models.map(function (model) { return model.id; }); + }; + SubsetOfCollection.prototype._validateNested = function () { return 0; }; + Object.defineProperty(SubsetOfCollection.prototype, "length", { + get: function () { + return this.models.length || (this.refs ? this.refs.length : 0); + }, + enumerable: true, + configurable: true + }); + SubsetOfCollection.prototype.clone = function (owner) { + var Ctor = this.constructor, copy = new Ctor([], { + model: this.model, + comparator: this.comparator + }); + if (this.resolvedWith) { + copy.resolvedWith = this.resolvedWith; + copy.refs = null; + copy.reset(this.models, { silent: true }); + } + else { + copy.refs = this.refs.slice(); + } + return copy; + }; + SubsetOfCollection.prototype.parse = function (raw) { + return raw; + }; + SubsetOfCollection.prototype.resolve = function (collection) { + if (collection && collection.length) { + this.resolvedWith = collection; + if (this.refs) { + this.reset(this.refs, { silent: true }); + this.refs = null; + } + } + return this; + }; + SubsetOfCollection.prototype.getModelIds = function () { return this.toJSON(); }; + SubsetOfCollection.prototype.toggle = function (modelOrId, val) { + return _super.prototype.toggle.call(this, this.resolvedWith.get(modelOrId), val); + }; + SubsetOfCollection.prototype.addAll = function () { + if (this.resolvedWith) { + this.set(this.resolvedWith.models); + return this.models; + } + throw new Error("Cannot add elemens because the subset collection is not resolved yet."); + }; + SubsetOfCollection.prototype.toggleAll = function () { + return this.length ? this.reset() : this.addAll(); + }; + SubsetOfCollection = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["define"] + ], SubsetOfCollection); + return SubsetOfCollection; + }(CollectionClass)); + SubsetOfCollection.prototype._itemEvents = void 0; + return SubsetOfCollection; +} +; +function resolveRefs(master, elements) { + var records = []; + for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) { + var el = elements_1[_i]; + var record = master.get(el); + if (record) + records.push(record); + } + return records; +} +function delaySet(collection, elements, options) { + if (_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["tools"].notEqual(collection.refs, elements)) { + var isRoot = _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].begin(collection); + collection.refs = elements.slice(); + _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].markAsDirty(collection, options); + isRoot && _transactions__WEBPACK_IMPORTED_MODULE_4__["transactionApi"].commit(collection); + } +} +function toArray(elements) { + return elements ? (Array.isArray(elements) ? elements : [elements]) : []; +} + + +/***/ }), + +/***/ "../../models/lib/transactions.js": +/*!*****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/transactions.js ***! + \*****************************************************************/ +/*! exports provided: ItemsBehavior, Transactional, transactionApi */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ItemsBehavior", function() { return ItemsBehavior; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Transactional", function() { return Transactional; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transactionApi", function() { return transactionApi; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _io_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./io-tools */ "../../models/lib/io-tools.js"); +/* harmony import */ var _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @type-r/mixture */ "../../mixture/lib/index.js"); +/* harmony import */ var _traversable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./traversable */ "../../models/lib/traversable.js"); +/* harmony import */ var _validation__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./validation */ "../../models/lib/validation.js"); +/* harmony import */ var _linked_value_lib__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @linked/value/lib */ "../../node_modules/@linked/value/lib/index.js"); + + + + + + +var trigger3 = _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["eventsApi"].trigger3, on = _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["eventsApi"].on, off = _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["eventsApi"].off; +var ItemsBehavior; +(function (ItemsBehavior) { + ItemsBehavior[ItemsBehavior["share"] = 1] = "share"; + ItemsBehavior[ItemsBehavior["listen"] = 2] = "listen"; + ItemsBehavior[ItemsBehavior["persistent"] = 4] = "persistent"; +})(ItemsBehavior || (ItemsBehavior = {})); +var Transactional = (function () { + function Transactional(cid) { + this._changeToken = {}; + this._transaction = false; + this._isDirty = null; + this._owner = void 0; + this._ownerKey = void 0; + this._validationError = void 0; + this.cid = this.cidPrefix + cid; + } + Transactional_1 = Transactional; + Transactional.onDefine = function (definitions, BaseClass) { + if (definitions.endpoint) + this.prototype._endpoint = definitions.endpoint; + _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["Messenger"].onDefine.call(this, definitions, BaseClass); + }; + ; + Transactional.onExtend = function (BaseClass) { + if (BaseClass.create === this.create) { + this.create = Transactional_1.create; + } + }; + Transactional.create = function (a, b) { + return new this(a, b); + }; + Transactional.prototype.dispose = function () { + if (this._disposed) + return; + Object(_io_tools__WEBPACK_IMPORTED_MODULE_1__["abortIO"])(this); + this._owner = void 0; + this._ownerKey = void 0; + this.off(); + this.stopListening(); + this._disposed = true; + }; + Transactional.prototype.onChanges = function (handler, target) { + on(this, this._changeEventName, handler, target); + }; + Transactional.prototype.offChanges = function (handler, target) { + off(this, this._changeEventName, handler, target); + }; + Transactional.prototype.listenToChanges = function (target, handler) { + this.listenTo(target, target._changeEventName, handler); + }; + Transactional.prototype.transaction = function (fun, options) { + if (options === void 0) { options = {}; } + var isRoot = transactionApi.begin(this); + var update = fun.call(this, this); + update && this.set(update); + isRoot && transactionApi.commit(this); + }; + Transactional.prototype.assignFrom = function (a_source) { + var _this = this; + var source = a_source instanceof _linked_value_lib__WEBPACK_IMPORTED_MODULE_5__["Linked"] ? a_source.value : a_source; + this.transaction(function () { + _this.set(source.__inner_state__ || source, { merge: true }); + var _changeToken = source._changeToken; + if (_changeToken) { + _this._changeToken = _changeToken; + } + }); + return this; + }; + Transactional.from = function (json, _a) { + if (_a === void 0) { _a = {}; } + var strict = _a.strict, options = tslib__WEBPACK_IMPORTED_MODULE_0__["__rest"](_a, ["strict"]); + var obj = this.create(json, tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({}, options, { logger: strict ? _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["throwingLogger"] : void 0 })); + if (strict && obj.validationError) { + obj.eachValidationError(function (error, key, obj) { + throw new Error(obj.getClassName() + "." + key + ": " + error); + }); + } + return obj; + }; + Transactional.prototype.parse = function (data, options) { return data; }; + Transactional.prototype.deepGet = function (reference) { + return Object(_traversable__WEBPACK_IMPORTED_MODULE_3__["resolveReference"])(this, reference, function (object, key) { return object.get ? object.get(key) : object[key]; }); + }; + Transactional.prototype.getOwner = function () { + return this._owner; + }; + Transactional.prototype.getStore = function () { + var _owner = this._owner; + return _owner ? _owner.getStore() : this._defaultStore; + }; + Transactional.prototype.hasPendingIO = function () { return this._ioPromise; }; + Transactional.prototype.getEndpoint = function () { + return getOwnerEndpoint(this) || this._endpoint; + }; + Object.defineProperty(Transactional.prototype, "validationError", { + get: function () { + var error = this._validationError || (this._validationError = new _validation__WEBPACK_IMPORTED_MODULE_4__["ValidationError"](this)); + return error.length ? error : null; + }, + enumerable: true, + configurable: true + }); + Transactional.prototype.validate = function (obj) { }; + Transactional.prototype.getValidationError = function (key) { + var error = this.validationError; + return (key ? error && error.nested[key] : error) || null; + }; + Transactional.prototype.deepValidationError = function (reference) { + return Object(_traversable__WEBPACK_IMPORTED_MODULE_3__["resolveReference"])(this, reference, function (object, key) { return object.getValidationError(key); }); + }; + Transactional.prototype.eachValidationError = function (iteratee) { + var validationError = this.validationError; + validationError && validationError.eachError(iteratee, this); + }; + Transactional.prototype.isValid = function (key) { + return !this.getValidationError(key); + }; + Transactional.prototype.valueOf = function () { return this.cid; }; + Transactional.prototype.toString = function () { return this.cid; }; + Transactional.prototype.getClassName = function () { + var name = this.constructor.name; + if (name !== 'Subclass') + return name; + }; + var Transactional_1; + Transactional = Transactional_1 = tslib__WEBPACK_IMPORTED_MODULE_0__["__decorate"]([ + _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["define"], + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["definitions"])({ + endpoint: _type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixinRules"].value + }), + Object(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["mixins"])(_type_r_mixture__WEBPACK_IMPORTED_MODULE_2__["Messenger"]) + ], Transactional); + return Transactional; +}()); + +var transactionApi = { + begin: function (object) { + return object._transaction ? false : (object._transaction = true); + }, + markAsDirty: function (object, options) { + var dirty = !options.silent; + if (dirty) + object._isDirty = options; + object._changeToken = {}; + object._validationError = void 0; + return dirty; + }, + commit: function (object, initiator) { + var originalOptions = object._isDirty; + if (originalOptions) { + while (object._isDirty) { + var options = object._isDirty; + object._isDirty = null; + trigger3(object, object._changeEventName, object, options, initiator); + } + object._transaction = false; + var _owner = object._owner; + if (_owner && _owner !== initiator) { + _owner._onChildrenChange(object, originalOptions); + } + } + else { + object._isDirty = null; + object._transaction = false; + } + }, + aquire: function (owner, child, key) { + if (child._owner) + throw new ReferenceError('Trying to aquire ownership for an object already having an owner'); + child._owner = owner; + child._ownerKey = key; + }, + free: function (owner, child) { + if (owner === child._owner) { + child._owner = void 0; + child._ownerKey = void 0; + } + } +}; +function getOwnerEndpoint(self) { + var collection = self.collection; + if (collection) { + return getOwnerEndpoint(collection); + } + if (self._owner) { + var _endpoints = self._owner._endpoints; + return _endpoints && _endpoints[self._ownerKey]; + } +} + + +/***/ }), + +/***/ "../../models/lib/traversable.js": +/*!****************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/traversable.js ***! + \****************************************************************/ +/*! exports provided: CompiledReference, resolveReference */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CompiledReference", function() { return CompiledReference; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resolveReference", function() { return resolveReference; }); +var referenceMask = /\^|(store\.[^.]+)|([^.]+)/g; +var CompiledReference = (function () { + function CompiledReference(reference, splitTail) { + if (splitTail === void 0) { splitTail = false; } + var path = reference + .match(referenceMask) + .map(function (key) { + if (key === '^' || key === 'owner') + return 'getOwner()'; + if (key[0] === '~') + return "getStore().get(\"" + key.substr(1) + "\")"; + if (key.indexOf('store.') === 0) + return "getStore().get(\"" + key.substr(6) + "\")"; + return key; + }); + this.tail = splitTail && path.pop(); + this.local = !path.length; + this.resolve = new Function('self', "\n var v = self." + path.shift() + ";\n \n " + path.map(function (x) { return "\n v = v && v." + x + ";\n "; }).join('') + "\n\n return v;\n "); + } + return CompiledReference; +}()); + +function resolveReference(root, reference, action) { + var path = reference.match(referenceMask), skip = path.length - 1; + var self = root; + for (var i = 0; i < skip; i++) { + var key = path[i]; + switch (key) { + case '~': + self = self.getStore(); + break; + case '^': + self = self.getOwner(); + break; + default: self = self.get(key); + } + if (!self) + return; + } + return action(self, path[skip]); +} + + +/***/ }), + +/***/ "../../models/lib/validation.js": +/*!***************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/models/lib/validation.js ***! + \***************************************************************/ +/*! exports provided: ValidationError */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ValidationError", function() { return ValidationError; }); +var ValidationError = (function () { + function ValidationError(obj) { + this.length = obj._validateNested(this.nested = {}); + if (this.error = obj.validate(obj)) { + this.length++; + } + } + ValidationError.prototype.each = function (iteratee) { + var _a = this, error = _a.error, nested = _a.nested; + if (error) + iteratee(error, null); + for (var key in nested) { + iteratee(nested[key], key); + } + }; + ValidationError.prototype.eachError = function (iteratee, object) { + this.each(function (value, key) { + if (value instanceof ValidationError) { + value.eachError(iteratee, object.get(key)); + } + else { + iteratee(value, key, object); + } + }); + }; + return ValidationError; +}()); + + + +/***/ }), + +/***/ "../../node_modules/@linked/react/lib/component.js": +/*!**********************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/@linked/react/lib/component.js ***! + \**********************************************************************************/ +/*! exports provided: LinkedComponent, StateLink */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinkedComponent", function() { return LinkedComponent; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StateLink", function() { return StateLink; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js"); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); + + + +var LinkedComponent = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](LinkedComponent, _super); + function LinkedComponent() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.links = null; + return _this; + } + // @deprecated use `this.$at( key )` + LinkedComponent.prototype.linkAt = function (key) { + return this.$at(key); + }; + // Get the link to the state member with the given key. + LinkedComponent.prototype.$at = function (key) { + var value = this.state[key], cache = this.links || (this.links = {}), cached = cache[key]; + return cached && cached.value === value ? + cached : + cache[key] = new StateLink(this, key, value); + }; + LinkedComponent.prototype.linkAll = function () { + return this.state$.apply(this, arguments); + }; + LinkedComponent.prototype.state$ = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var state = this.state, cache = this.links || (this.links = {}), keys = args.length ? args : Object.keys(state); + for (var _a = 0, keys_1 = keys; _a < keys_1.length; _a++) { + var key = keys_1[_a]; + var value = state[key], cached = cache[key]; + if (!cached || cached.value !== value) { + cache[key] = new StateLink(this, key, value); + } + } + return cache; + }; + return LinkedComponent; +}(react__WEBPACK_IMPORTED_MODULE_1__["Component"])); + +var StateLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](StateLink, _super); + function StateLink(component, key, value) { + var _this = _super.call(this, value) || this; + _this.component = component; + _this.key = key; + return _this; + } + StateLink.prototype.set = function (x) { + var attrs = {}; + attrs[this.key] = x; + this.component.setState(attrs); + }; + return StateLink; +}(_linked_value__WEBPACK_IMPORTED_MODULE_2__["Linked"])); + + + +/***/ }), + +/***/ "../../node_modules/@linked/react/lib/hooks.js": +/*!******************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/@linked/react/lib/hooks.js ***! + \******************************************************************************/ +/*! exports provided: useLink, useLinked, useSafeLinked, useSyncLinked, useSafeSyncLinked, useSafeLink, useIsMountedRef, useBoundLink, useSafeBoundLink, useLocalStorage, useIO, whenChanged */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useLink", function() { return useLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useLinked", function() { return useLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useSafeLinked", function() { return useSafeLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useSyncLinked", function() { return useBoundLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useSafeSyncLinked", function() { return useSafeBoundLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useSafeLink", function() { return useSafeLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useIsMountedRef", function() { return useIsMountedRef; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useBoundLink", function() { return useBoundLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useSafeBoundLink", function() { return useSafeBoundLink; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useLocalStorage", function() { return useLocalStorage; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useIO", function() { return useIO; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "whenChanged", function() { return whenChanged; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js"); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__); + + + +var LinkedUseState = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](LinkedUseState, _super); + function LinkedUseState(value, set) { + var _this = _super.call(this, value) || this; + _this.set = set; + return _this; + } + // Set the component's state value. + LinkedUseState.prototype.set = function (x) { }; + LinkedUseState.prototype.update = function (fun, event) { + // update function must be overriden to use state set + // ability to delay an update, and to preserve link.update semantic. + this.set(function (x) { + var value = Object(_linked_value__WEBPACK_IMPORTED_MODULE_1__["helpers"])(x).clone(x), result = fun(value, event); + return result === void 0 ? x : result; + }); + }; + return LinkedUseState; +}(_linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"])); +/** + * Create the ref to the local state. + */ +function useLink(initialState) { + var _a = Object(react__WEBPACK_IMPORTED_MODULE_2__["useState"])(initialState), value = _a[0], set = _a[1]; + return new LinkedUseState(value, set); +} + +/** + * Create the link to the local state which is safe to set when component is unmounted. + * Use this for the state which is set when async I/O is completed. + */ +function useSafeLink(initialState) { + var _a = Object(react__WEBPACK_IMPORTED_MODULE_2__["useState"])(initialState), value = _a[0], set = _a[1], isMounted = useIsMountedRef(); + return new LinkedUseState(value, function (x) { return isMounted.current && set(x); }); +} +/** + * Returns the ref which is true when component it mounted. + */ +function useIsMountedRef() { + var isMounted = Object(react__WEBPACK_IMPORTED_MODULE_2__["useRef"])(true); + Object(react__WEBPACK_IMPORTED_MODULE_2__["useEffect"])(function () { return (function () { return isMounted.current = false; }); }, []); + return isMounted; +} +/** + * Create the link to the local state which is bound to another + * value or link in a single direction. When the source changes, the link changes too. + */ +function useBoundLink(source) { + var value = source instanceof _linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"] ? source.value : source, link = useLink(value); + Object(react__WEBPACK_IMPORTED_MODULE_2__["useEffect"])(function () { return link.set(value); }, [value]); + link.action; + return link; +} +/** + * Create the safe link to the local state which is synchronized with another + * value or link in a single direction. + * When the source change, the linked state changes too. + */ +function useSafeBoundLink(source) { + var value = source instanceof _linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"] ? source.value : source, link = useSafeLink(value); + Object(react__WEBPACK_IMPORTED_MODULE_2__["useEffect"])(function () { return link.set(value); }, [value]); + return link; +} +/** + * Persists links in local storage under the given key. + * Links will be loaded on component's mount, and saved on unmount. + * @param key - string key for the localStorage entry. + * @param state - links to persist wrapped in an object `{ lnk1, lnk2, ... }` + */ +function useLocalStorage(key, state) { + // save state to use on unmount... + var stateRef = Object(react__WEBPACK_IMPORTED_MODULE_2__["useRef"])(); + stateRef.current = state; + Object(react__WEBPACK_IMPORTED_MODULE_2__["useEffect"])(function () { + var savedData = JSON.parse(localStorage.getItem(key) || '{}'); + _linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"].setValues(stateRef.current, savedData); + return function () { + var dataToSave = _linked_value__WEBPACK_IMPORTED_MODULE_1__["Linked"].getValues(stateRef.current); + localStorage.setItem(key, JSON.stringify(dataToSave)); + }; + }, []); +} +/** + * Wait for the promise (or async function) completion. + * Execute operation once when mounted, returning: + * - `false` while the I/O operation is pending; + * - `true` if I/O is complete without exception; + * - `exception` object if I/O promise failed. + * + * const isReady = useIO( async () => { + * const data = await fetchData(); + * link.set( data ); + * }); + */ +function useIO(fun, condition) { + if (condition === void 0) { condition = []; } + // Counter of open I/O requests. If it's 0, I/O is completed. + // Counter is needed to handle the situation when the next request + // is issued before the previous one was completed. + var $isReady = useSafeLink(null); + Object(react__WEBPACK_IMPORTED_MODULE_2__["useEffect"])(function () { + // function in set instead of value to avoid race conditions with counter increment. + $isReady.set(function (state) { + var _a = state || [0, null], x = _a[0], res = _a[1]; + return [x + 1, res]; + }); + fun() + .catch(function (e) { $isReady.set(function (_a) { + var x = _a[0], res = _a[1]; + return [x - 1, e]; + }); }) + .then(function () { $isReady.set(function (_a) { + var x = _a[0], res = _a[1]; + return [x - 1, null]; + }); }); + }, condition); + // `null` is used to detect the first render when no requests issued yet, + // but the I/O is not completed. + var value = $isReady.value; + return value === null || value[0] ? false : (value[1] || true); +} +function whenChanged(a, b, c, d) { + var length = arguments.length; + switch (length) { + case 1: return [extractChangeToken(a)]; + case 2: return [extractChangeToken(a), extractChangeToken(b)]; + case 3: return [extractChangeToken(a), extractChangeToken(b), extractChangeToken(c)]; + default: + var array = [extractChangeToken(a), extractChangeToken(b), extractChangeToken(c), extractChangeToken(d)]; + for (var i = 4; i < length; i++) { + array.push(extractChangeToken(arguments[i])); + } + return array; + } +} +function extractChangeToken(x) { + return x && x._changeToken !== void 0 ? x._changeToken : x; +} + + +/***/ }), + +/***/ "../../node_modules/@linked/react/lib/index.js": +/*!******************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/@linked/react/lib/index.js ***! + \******************************************************************************/ +/*! exports provided: default, Link, LinkedComponent, StateLink, Linked, PropValueLink, useLink, useLinked, useSafeLinked, useSyncLinked, useSafeSyncLinked, useSafeLink, useIsMountedRef, useBoundLink, useSafeBoundLink, useLocalStorage, useIO, whenChanged, helpers, objectHelpers, arrayHelpers */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _linked_value__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @linked/value */ "../../node_modules/@linked/value/lib/index.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Link", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["Linked"]; }); + +/* harmony import */ var _component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./component */ "../../node_modules/@linked/react/lib/component.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "LinkedComponent", function() { return _component__WEBPACK_IMPORTED_MODULE_1__["LinkedComponent"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "StateLink", function() { return _component__WEBPACK_IMPORTED_MODULE_1__["StateLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Linked", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["Linked"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PropValueLink", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["PropValueLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "helpers", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["helpers"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "objectHelpers", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["objectHelpers"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "arrayHelpers", function() { return _linked_value__WEBPACK_IMPORTED_MODULE_0__["arrayHelpers"]; }); + +/* harmony import */ var _hooks__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./hooks */ "../../node_modules/@linked/react/lib/hooks.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useLink", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useLinked", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useLinked"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useSafeLinked", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useSafeLinked"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useSyncLinked", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useSyncLinked"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useSafeSyncLinked", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useSafeSyncLinked"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useSafeLink", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useSafeLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useIsMountedRef", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useIsMountedRef"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useBoundLink", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useBoundLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useSafeBoundLink", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useSafeBoundLink"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useLocalStorage", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useLocalStorage"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useIO", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["useIO"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "whenChanged", function() { return _hooks__WEBPACK_IMPORTED_MODULE_2__["whenChanged"]; }); + + +/* harmony default export */ __webpack_exports__["default"] = (_linked_value__WEBPACK_IMPORTED_MODULE_0__["Linked"]); +/** @deprecated, use `Linked` instead */ + + + + + + +/***/ }), + +/***/ "../../node_modules/@linked/value/lib/helpers.js": +/*!********************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/@linked/value/lib/helpers.js ***! + \********************************************************************************/ +/*! exports provided: helpers, objectHelpers, arrayHelpers */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "helpers", function() { return helpers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "objectHelpers", function() { return objectHelpers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "arrayHelpers", function() { return arrayHelpers; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); + +var ArrayProto = Array.prototype, ObjectProto = Object.prototype; +function helpers(value) { + if (value && typeof value === 'object') { + switch (Object.getPrototypeOf(value)) { + case ArrayProto: return arrayHelpers; + case ObjectProto: return objectHelpers; + } + } + return dummyHelpers; +} +// Do nothing for types other than Array and plain Object. +var dummyHelpers = { + clone: function (value) { return value; }, + map: function (link, fun) { return []; }, + remove: function (value) { return value; } +}; +// `map` and `clone` for plain JS objects +var objectHelpers = { + // Map through the link to object + map: function (link, iterator) { + var mapped = [], value = link.value; + for (var key in value) { + if (value.hasOwnProperty(key)) { + var element = iterator(link.at(key), key); + element === void 0 || (mapped.push(element)); + } + } + return mapped; + }, + remove: function (object, key) { + delete object[key]; + return object; + }, + // Shallow clone plain JS object + clone: function (object) { + return tslib__WEBPACK_IMPORTED_MODULE_0__["__assign"]({}, object); + } +}; +// `map` and `clone` helpers for arrays. +var arrayHelpers = { + // Shallow clone array + clone: function (array) { + return array.slice(); + }, + remove: function (array, i) { + array.splice(i, 1); + return array; + }, + // Map through the link to array + map: function (link, iterator) { + var length = link.value.length, mapped = Array(length); + for (var i = 0, j = 0; i < length; i++) { + var y = iterator(link.at(i), i); + y === void 0 || (mapped[j++] = y); + } + mapped.length === j || (mapped.length = j); + return mapped; + } +}; + + +/***/ }), + +/***/ "../../node_modules/@linked/value/lib/index.js": +/*!******************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/@linked/value/lib/index.js ***! + \******************************************************************************/ +/*! exports provided: Linked, PropValueLink, helpers, objectHelpers, arrayHelpers */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Linked", function() { return Linked; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PropValueLink", function() { return PropValueLink; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js"); +/* harmony import */ var _helpers__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./helpers */ "../../node_modules/@linked/value/lib/helpers.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "helpers", function() { return _helpers__WEBPACK_IMPORTED_MODULE_1__["helpers"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "objectHelpers", function() { return _helpers__WEBPACK_IMPORTED_MODULE_1__["objectHelpers"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "arrayHelpers", function() { return _helpers__WEBPACK_IMPORTED_MODULE_1__["arrayHelpers"]; }); + + +/** + * Advanced React links for purely functional two-way data binding + * + * MIT License, (c) 2016 Vlad Balin, Volicon. + */ + + +/** + * `Linked` class is an abstract linked value - the value, the function to update this value, and its validation error. + * The enclosed value is considered as immutable. + */ +var Linked = /** @class */ (function () { + function Linked(value) { + this.value = value; + /** Validation error. Usually is a string with error text, but can hold any type. */ + this.error = void 0; + } + Object.defineProperty(Linked.prototype, "current", { + /** EXPERIMENTAL: Support useRef interface. */ + get: function () { return this.value; }, + set: function (x) { this.set(x); }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Linked.prototype, "_changeToken", { + // Private accessor for whenChanged. Uniform with Type-R models and collections API. + get: function () { + return this.value; + }, + enumerable: true, + configurable: true + }); + /** Produce the new link executing the given function before the link value will be updated. */ + Linked.prototype.onChange = function (handler) { + var _this = this; + return new ClonedValueLink(this, function (x) { + handler(x); + _this.set(x); + }); + }; + /** Produce the new link which transform the value before `set` with a given function. */ + Linked.prototype.pipe = function (handler) { + var _this = this; + return new ClonedValueLink(this, function (x) { + var next = handler(x, _this.value); + next === void 0 || _this.set(next); + }); + }; + Object.defineProperty(Linked.prototype, "props", { + /** + * Create React component props for the component. + * + * + */ + get: function () { + var _this = this; + return typeof this.value === 'boolean' ? { + checked: this.value, + onChange: function (e) { return _this.set(Boolean(e.target.checked)); } + } : { + value: this.value, + onChange: function (e) { return _this.set(e.target.value); } + }; + }, + enumerable: true, + configurable: true + }); + /** Update the linked value using given transform function. */ + Linked.prototype.update = function (transform, e) { + var next = transform(this.clone(), e); + next === void 0 || this.set(next); + }; + // Create UI event handler function which will update the link with a given transform function. + Linked.prototype.action = function (transform) { + var _this = this; + return function (e) { return _this.update(transform, e); }; + }; + Linked.prototype.equals = function (truthyValue) { + return new EqualsValueLink(this, truthyValue); + }; + Linked.prototype.enabled = function (defaultValue) { + return new EnabledValueLink(this, defaultValue || ""); + }; + // Array-only links methods + Linked.prototype.contains = function (element) { + return new ContainsRef(this, element); + }; + Linked.prototype.push = function () { + var array = _helpers__WEBPACK_IMPORTED_MODULE_1__["arrayHelpers"].clone(this.value); + Array.prototype.push.apply(array, arguments); + this.set(array); + }; + Linked.prototype.unshift = function () { + var array = _helpers__WEBPACK_IMPORTED_MODULE_1__["arrayHelpers"].clone(this.value); + Array.prototype.unshift.apply(array, arguments); + this.set(array); + }; + Linked.prototype.splice = function () { + var array = _helpers__WEBPACK_IMPORTED_MODULE_1__["arrayHelpers"].clone(this.value); + Array.prototype.splice.apply(array, arguments); + this.set(array); + }; + Linked.prototype.map = function (iterator) { + return Object(_helpers__WEBPACK_IMPORTED_MODULE_1__["helpers"])(this.value).map(this, iterator); + }; + Linked.prototype.removeAt = function (key) { + var value = this.value, _ = Object(_helpers__WEBPACK_IMPORTED_MODULE_1__["helpers"])(value); + this.set(_.remove(_.clone(value), key)); + }; + Linked.prototype.at = function (key) { + return new PropValueLink(this, key); + }; + Linked.prototype.clone = function () { + var value = this.value; + return Object(_helpers__WEBPACK_IMPORTED_MODULE_1__["helpers"])(value).clone(value); + }; + Linked.prototype.pick = function () { + var links = {}, keys = arguments.length ? arguments : Object.keys(this.value); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + links[key] = new PropValueLink(this, key); + } + return links; + }; + Object.defineProperty(Linked.prototype, "$", { + /** + * Convert link to object to the object of links. + * Memorises the result, subsequent calls are cheap. + */ + get: function () { + if (!this._value$) { + var links = this._value$ = {}, value = this.value; + for (var key in value) { + if (value.hasOwnProperty(key)) { + links[key] = new PropValueLink(this, key); + } + } + } + return this._value$; + }, + enumerable: true, + configurable: true + }); + /** + * Validate link with validness predicate and optional custom error object. Can be chained. + */ + Linked.prototype.check = function (whenValid, error) { + if (!this.error && !whenValid(this.value)) { + this.error = error || whenValid.error || defaultError; + } + return this; + }; + return Linked; +}()); + +(function (Linked) { + /** Create linked value out of its value and the set function */ + function value(value, set) { + return new CustomValueLink(value, set); + } + Linked.value = value; + /** + * Unwrap object with links, returning an object of a similar shape filled with link values. + */ + function getValues(links) { + return unwrap(links, 'value'); + } + Linked.getValues = getValues; + /** + * Unwrap object with links, returning an object of a similar shape filled with link errors. + */ + function getErrors(links) { + return unwrap(links, 'error'); + } + Linked.getErrors = getErrors; + /** + * Return true if an object with links contains any errors. + */ + function hasErrors(links) { + for (var key in links) { + if (links.hasOwnProperty(key) && links[key].error) { + return true; + } + } + return false; + } + Linked.hasErrors = hasErrors; + /** + * Assing links with values from the source object. + */ + function setValues(links, source) { + if (source) { + for (var key in links) { + var sourceKey = trim(key); + if (source.hasOwnProperty(sourceKey)) { + var sourceVal = source[sourceKey]; + sourceVal === void 0 || links[key].set(sourceVal); + } + } + } + } + Linked.setValues = setValues; +})(Linked || (Linked = {})); +var CustomValueLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CustomValueLink, _super); + function CustomValueLink(value, set) { + var _this = _super.call(this, value) || this; + _this.set = set; + return _this; + } + CustomValueLink.prototype.set = function (x) { }; + return CustomValueLink; +}(Linked)); +var ClonedValueLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ClonedValueLink, _super); + function ClonedValueLink(parent, set) { + var _this = _super.call(this, parent.value) || this; + _this.set = set; + var error = parent.error; + if (error) + _this.error = error; + return _this; + } + ClonedValueLink.prototype.set = function (x) { }; + return ClonedValueLink; +}(Linked)); +var EqualsValueLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](EqualsValueLink, _super); + function EqualsValueLink(parent, truthyValue) { + var _this = _super.call(this, parent.value === truthyValue) || this; + _this.parent = parent; + _this.truthyValue = truthyValue; + return _this; + } + EqualsValueLink.prototype.set = function (x) { + this.parent.set(x ? this.truthyValue : null); + }; + return EqualsValueLink; +}(Linked)); +var EnabledValueLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](EnabledValueLink, _super); + function EnabledValueLink(parent, defaultValue) { + var _this = _super.call(this, parent.value != null) || this; + _this.parent = parent; + _this.defaultValue = defaultValue; + return _this; + } + EnabledValueLink.prototype.set = function (x) { + this.parent.set(x ? this.defaultValue : null); + }; + return EnabledValueLink; +}(Linked)); +var ContainsRef = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ContainsRef, _super); + function ContainsRef(parent, element) { + var _this = _super.call(this, parent.value.indexOf(element) >= 0) || this; + _this.parent = parent; + _this.element = element; + return _this; + } + ContainsRef.prototype.set = function (x) { + var _this = this; + var next = Boolean(x); + if (this.value !== next) { + var arr = this.parent.value, nextValue = x ? arr.concat(this.element) : arr.filter(function (el) { return el !== _this.element; }); + this.parent.set(nextValue); + } + }; + return ContainsRef; +}(Linked)); +var defaultError = 'Invalid value'; +/** + * Link to array or object element enclosed in parent link. + * Performs purely functional update of the parent, shallow copying its value on `set`. + */ +var PropValueLink = /** @class */ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](PropValueLink, _super); + function PropValueLink(parent, key) { + var _this = _super.call(this, parent.value[key]) || this; + _this.parent = parent; + _this.key = key; + return _this; + } + PropValueLink.prototype.remove = function () { + this.parent.removeAt(this.key); + }; + // Set new element value to parent array or object, performing purely functional update. + PropValueLink.prototype.set = function (x) { + var _this = this; + if (this.value !== x) { + this.parent.update(function (value) { + value[_this.key] = x; + return value; + }); + } + }; + ; + return PropValueLink; +}(Linked)); + +function unwrap(links, field) { + var values = {}; + for (var key in links) { + if (links.hasOwnProperty(key)) { + var value = links[key][field]; + if (value !== void 0) { + values[trim(key)] = value; + } + } + } + return values; +} +function trim(key) { + return key[0] === '$' ? key.slice(1) : key; +} + + +/***/ }), + +/***/ "../../node_modules/css-loader/dist/cjs.js?!./src/styles.css": +/*!*****************************************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/css-loader/dist/cjs.js??ref--4-1!./src/styles.css ***! + \*****************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ "../../node_modules/css-loader/dist/runtime/api.js")(false); +// Module +exports.push([module.i, "input {\n margin : 1em;\n border-radius: 2px;\n}", ""]); + + +/***/ }), + +/***/ "../../node_modules/css-loader/dist/runtime/api.js": +/*!**********************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/css-loader/dist/runtime/api.js ***! + \**********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// css base code, injected by the css-loader +// eslint-disable-next-line func-names +module.exports = function (useSourceMap) { + var list = []; // return the list of modules as css string + + list.toString = function toString() { + return this.map(function (item) { + var content = cssWithMappingToString(item, useSourceMap); + + if (item[2]) { + return "@media ".concat(item[2], "{").concat(content, "}"); + } + + return content; + }).join(''); + }; // import a list of modules into the list + // eslint-disable-next-line func-names + + + list.i = function (modules, mediaQuery) { + if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign + modules = [[null, modules, '']]; + } + + var alreadyImportedModules = {}; + + for (var i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + var id = this[i][0]; + + if (id != null) { + alreadyImportedModules[id] = true; + } + } + + for (var _i = 0; _i < modules.length; _i++) { + var item = modules[_i]; // skip already imported module + // this implementation is not 100% perfect for weird media query combinations + // when a module is imported multiple times with different media queries. + // I hope this will never occur (Hey this way we have smaller bundles) + + if (item[0] == null || !alreadyImportedModules[item[0]]) { + if (mediaQuery && !item[2]) { + item[2] = mediaQuery; + } else if (mediaQuery) { + item[2] = "(".concat(item[2], ") and (").concat(mediaQuery, ")"); + } + + list.push(item); + } + } + }; + + return list; +}; + +function cssWithMappingToString(item, useSourceMap) { + var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring + + var cssMapping = item[3]; + + if (!cssMapping) { + return content; + } + + if (useSourceMap && typeof btoa === 'function') { + var sourceMapping = toComment(cssMapping); + var sourceURLs = cssMapping.sources.map(function (source) { + return "/*# sourceURL=".concat(cssMapping.sourceRoot).concat(source, " */"); + }); + return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); + } + + return [content].join('\n'); +} // Adapted from convert-source-map (MIT) + + +function toComment(sourceMap) { + // eslint-disable-next-line no-undef + var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + var data = "sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(base64); + return "/*# ".concat(data, " */"); +} + +/***/ }), + +/***/ "../../node_modules/object-assign/index.js": +/*!**************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/object-assign/index.js ***! + \**************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + + +/* eslint-disable no-unused-vars */ +var getOwnPropertySymbols = Object.getOwnPropertySymbols; +var hasOwnProperty = Object.prototype.hasOwnProperty; +var propIsEnumerable = Object.prototype.propertyIsEnumerable; + +function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } + + return Object(val); +} + +function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } + + // Detect buggy property enumeration order in older V8 versions. + + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } + + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } +} + +module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; + + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } + + return to; +}; + + +/***/ }), + +/***/ "../../node_modules/process/browser.js": +/*!**********************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/process/browser.js ***! + \**********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + + +/***/ }), + +/***/ "../../node_modules/prop-types/checkPropTypes.js": +/*!********************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/prop-types/checkPropTypes.js ***! + \********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +var printWarning = function() {}; + +if (true) { + var ReactPropTypesSecret = __webpack_require__(/*! ./lib/ReactPropTypesSecret */ "../../node_modules/prop-types/lib/ReactPropTypesSecret.js"); + var loggedTypeFailures = {}; + var has = Function.call.bind(Object.prototype.hasOwnProperty); + + printWarning = function(text) { + var message = 'Warning: ' + text; + if (typeof console !== 'undefined') { + console.error(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; +} + +/** + * Assert that the values match with the type specs. + * Error messages are memorized and will only be shown once. + * + * @param {object} typeSpecs Map of name to a ReactPropType + * @param {object} values Runtime values that need to be type-checked + * @param {string} location e.g. "prop", "context", "child context" + * @param {string} componentName Name of the component for error messages. + * @param {?Function} getStack Returns the component stack. + * @private + */ +function checkPropTypes(typeSpecs, values, location, componentName, getStack) { + if (true) { + for (var typeSpecName in typeSpecs) { + if (has(typeSpecs, typeSpecName)) { + var error; + // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + if (typeof typeSpecs[typeSpecName] !== 'function') { + var err = Error( + (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + ); + err.name = 'Invariant Violation'; + throw err; + } + error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); + } catch (ex) { + error = ex; + } + if (error && !(error instanceof Error)) { + printWarning( + (componentName || 'React class') + ': type specification of ' + + location + ' `' + typeSpecName + '` is invalid; the type checker ' + + 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' + + 'You may have forgotten to pass an argument to the type checker ' + + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + + 'shape all require an argument).' + ); + } + if (error instanceof Error && !(error.message in loggedTypeFailures)) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error.message] = true; + + var stack = getStack ? getStack() : ''; + + printWarning( + 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '') + ); + } + } + } + } +} + +/** + * Resets warning cache when testing. + * + * @private + */ +checkPropTypes.resetWarningCache = function() { + if (true) { + loggedTypeFailures = {}; + } +} + +module.exports = checkPropTypes; + + +/***/ }), + +/***/ "../../node_modules/prop-types/lib/ReactPropTypesSecret.js": +/*!******************************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/prop-types/lib/ReactPropTypesSecret.js ***! + \******************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; + +module.exports = ReactPropTypesSecret; + + +/***/ }), + +/***/ "../../node_modules/react-dom/cjs/react-dom.development.js": +/*!******************************************************************************************!*\ + !*** /Users/vladbalin/GitHub/Type-R/node_modules/react-dom/cjs/react-dom.development.js ***! + \******************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** @license React v16.8.6 + * react-dom.development.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + + + +if (true) { + (function() { +'use strict'; + +var React = __webpack_require__(/*! react */ "../../node_modules/react/index.js"); +var _assign = __webpack_require__(/*! object-assign */ "../../node_modules/object-assign/index.js"); +var checkPropTypes = __webpack_require__(/*! prop-types/checkPropTypes */ "../../node_modules/prop-types/checkPropTypes.js"); +var scheduler = __webpack_require__(/*! scheduler */ "../../node_modules/scheduler/index.js"); +var tracing = __webpack_require__(/*! scheduler/tracing */ "../../node_modules/scheduler/tracing.js"); + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +var validateFormat = function () {}; + +{ + validateFormat = function (format) { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + }; +} + +function invariant(condition, format, a, b, c, d, e, f) { + validateFormat(format); + + if (!condition) { + var error = void 0; + if (format === undefined) { + error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error(format.replace(/%s/g, function () { + return args[argIndex++]; + })); + error.name = 'Invariant Violation'; + } + + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } +} + +// Relying on the `invariant()` implementation lets us +// preserve the format and params in the www builds. + +!React ? invariant(false, 'ReactDOM was loaded before React. Make sure you load the React package before loading ReactDOM.') : void 0; + +var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +}; + +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // unintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! + + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') { + var fakeNode = document.createElement('react'); + + var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + !(typeof document !== 'undefined') ? invariant(false, 'The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous.') : void 0; + var evt = document.createEvent('Event'); + + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; + + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor(window, 'event'); + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) { + window.event = windowEvent; + } + + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === 'object') { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } + } + } + + // Create a fake event type. + var evtType = 'react-' + (name ? name : 'invokeguardedcallback'); + + // Attach our event handlers + window.addEventListener('error', handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, 'event', windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.'); + } else if (isCrossOriginError) { + error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.'); + } + this.onError(error); + } + + // Remove our event listeners + window.removeEventListener('error', handleWindowError); + }; + + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; + +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; + +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function (error) { + hasError = true; + caughtError = error; + } +}; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} + +function hasCaughtError() { + return hasError; +} + +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + invariant(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.'); + } +} + +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + !(pluginIndex > -1) ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.', pluginName) : void 0; + if (plugins[pluginIndex]) { + continue; + } + !pluginModule.extractEvents ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.', pluginName) : void 0; + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + !publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : void 0; + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + !!eventNameDispatchConfigs.hasOwnProperty(eventName) ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.', eventName) : void 0; + eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName(phasedRegistrationName, pluginModule, eventName); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + !!registrationNameModules[registrationName] ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.', registrationName) : void 0; + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies; + + { + var lowerCasedName = registrationName.toLowerCase(); + possibleRegistrationNames[lowerCasedName] = registrationName; + + if (registrationName === 'onDoubleClick') { + possibleRegistrationNames.ondblclick = registrationName; + } + } +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + +/** + * Ordered list of injected plugins. + */ +var plugins = []; + +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; + +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; + +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; + +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ +var possibleRegistrationNames = {}; +// Trust the developer to only use possibleRegistrationNames in true + +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + !!eventPluginOrder ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.') : void 0; + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var pluginModule = injectedNamesToPlugins[pluginName]; + if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) { + !!namesToPlugins[pluginName] ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.', pluginName) : void 0; + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warningWithoutStack = function () {}; + +{ + warningWithoutStack = function (condition, format) { + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error('`warningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument'); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error('warningWithoutStack() currently supports at most 8 arguments.'); + } + if (condition) { + return; + } + if (typeof console !== 'undefined') { + var argsWithFormat = args.map(function (item) { + return '' + item; + }); + argsWithFormat.unshift('Warning: ' + format); + + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function () { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} + +var warningWithoutStack$1 = warningWithoutStack; + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) ? warningWithoutStack$1(false, 'EventPluginUtils.setComponentTree(...): Injected ' + 'module is missing getNodeFromInstance or getInstanceFromNode.') : void 0; + } +} + +var validateEventDispatches = void 0; +{ + validateEventDispatches = function (event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0; + + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr ? dispatchInstances.length : dispatchInstances ? 1 : 0; + + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) ? warningWithoutStack$1(false, 'EventPluginUtils: Invalid `event`.') : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || 'unknown-event'; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ + + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ + + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + +function accumulateInto(current, next) { + !(next != null) ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : void 0; + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; + } + current.push(next); + return current; + } + + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; +} + +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function (event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseTopLevel = function (e) { + return executeDispatchesAndRelease(e); +}; + +function isInteractive(tag) { + return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea'; +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case 'onClick': + case 'onClickCapture': + case 'onDoubleClick': + case 'onDoubleClickCapture': + case 'onMouseDown': + case 'onMouseDownCapture': + case 'onMouseMove': + case 'onMouseMoveCapture': + case 'onMouseUp': + case 'onMouseUpCapture': + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; + +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + !(!listener || typeof listener === 'function') ? invariant(false, 'Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener) : void 0; + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; +} + +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } + + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + !!eventQueue ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.') : void 0; + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} + +function runExtractedEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget); + runEventsInBatch(events); +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; + +var randomKey = Math.random().toString(36).slice(2); +var internalInstanceKey = '__reactInternalInstance$' + randomKey; +var internalEventHandlersKey = '__reactEventHandlers$' + randomKey; + +function precacheFiberNode(hostInst, node) { + node[internalInstanceKey] = hostInst; +} + +/** + * Given a DOM node, return the closest ReactDOMComponent or + * ReactDOMTextComponent instance ancestor. + */ +function getClosestInstanceFromNode(node) { + if (node[internalInstanceKey]) { + return node[internalInstanceKey]; + } + + while (!node[internalInstanceKey]) { + if (node.parentNode) { + node = node.parentNode; + } else { + // Top of the tree. This node must not be part of a React tree (or is + // unmounted, potentially). + return null; + } + } + + var inst = node[internalInstanceKey]; + if (inst.tag === HostComponent || inst.tag === HostText) { + // In Fiber, this will always be the deepest root. + return inst; + } + + return null; +} + +/** + * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent + * instance, or null if the node was not rendered by this React. + */ +function getInstanceFromNode$1(node) { + var inst = node[internalInstanceKey]; + if (inst) { + if (inst.tag === HostComponent || inst.tag === HostText) { + return inst; + } else { + return null; + } + } + return null; +} + +/** + * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding + * DOM node. + */ +function getNodeFromInstance$1(inst) { + if (inst.tag === HostComponent || inst.tag === HostText) { + // In Fiber this, is just the state node right now. We assume it will be + // a host component or host text. + return inst.stateNode; + } + + // Without this first invariant, passing a non-DOM-component triggers the next + // invariant for a missing parent, which is super confusing. + invariant(false, 'getNodeFromInstance: Invalid argument.'); +} + +function getFiberCurrentPropsFromNode$1(node) { + return node[internalEventHandlersKey] || null; +} + +function updateFiberProps(node, props) { + node[internalEventHandlersKey] = props; +} + +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} + +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; + } + + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } + + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} + +/** + * Return if A is an ancestor of B. + */ + + +/** + * Return the parent instance of the passed-in instance. + */ + + +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i = void 0; + for (i = path.length; i-- > 0;) { + fn(path[i], 'captured', arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], 'bubbled', arg); + } +} + +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ +function traverseEnterLeave(from, to, fn, argFrom, argTo) { + var common = from && to ? getLowestCommonAncestor(from, to) : null; + var pathFrom = []; + while (true) { + if (!from) { + break; + } + if (from === common) { + break; + } + var alternate = from.alternate; + if (alternate !== null && alternate === common) { + break; + } + pathFrom.push(from); + from = getParent(from); + } + var pathTo = []; + while (true) { + if (!to) { + break; + } + if (to === common) { + break; + } + var _alternate = to.alternate; + if (_alternate !== null && _alternate === common) { + break; + } + pathTo.push(to); + to = getParent(to); + } + for (var i = 0; i < pathFrom.length; i++) { + fn(pathFrom[i], 'bubbled', argFrom); + } + for (var _i = pathTo.length; _i-- > 0;) { + fn(pathTo[_i], 'captured', argTo); + } +} + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst ? warningWithoutStack$1(false, 'Dispatching inst must not be null') : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto(event._dispatchListeners, listener); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + + + +function accumulateEnterLeaveDispatches(leave, enter, from, to) { + traverseEnterLeave(from, to, accumulateDispatches, leave, enter); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + +var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + +// Do not uses the below two methods directly! +// Instead use constants exported from DOMTopLevelEventTypes in ReactDOM. +// (It is the only module that is allowed to access these methods.) + +function unsafeCastStringToDOMTopLevelType(topLevelType) { + return topLevelType; +} + +function unsafeCastDOMTopLevelTypeToString(topLevelType) { + return topLevelType; +} + +/** + * Generate a mapping of standard vendor prefixes using the defined style property and event name. + * + * @param {string} styleProp + * @param {string} eventName + * @returns {object} + */ +function makePrefixMap(styleProp, eventName) { + var prefixes = {}; + + prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); + prefixes['Webkit' + styleProp] = 'webkit' + eventName; + prefixes['Moz' + styleProp] = 'moz' + eventName; + + return prefixes; +} + +/** + * A list of event names to a configurable list of vendor prefixes. + */ +var vendorPrefixes = { + animationend: makePrefixMap('Animation', 'AnimationEnd'), + animationiteration: makePrefixMap('Animation', 'AnimationIteration'), + animationstart: makePrefixMap('Animation', 'AnimationStart'), + transitionend: makePrefixMap('Transition', 'TransitionEnd') +}; + +/** + * Event names that have already been detected and prefixed (if applicable). + */ +var prefixedEventNames = {}; + +/** + * Element to check for prefixes on. + */ +var style = {}; + +/** + * Bootstrap if a DOM exists. + */ +if (canUseDOM) { + style = document.createElement('div').style; + + // On some platforms, in particular some releases of Android 4.x, + // the un-prefixed "animation" and "transition" properties are defined on the + // style object but the events that fire will still be prefixed, so we need + // to check if the un-prefixed events are usable, and if not remove them from the map. + if (!('AnimationEvent' in window)) { + delete vendorPrefixes.animationend.animation; + delete vendorPrefixes.animationiteration.animation; + delete vendorPrefixes.animationstart.animation; + } + + // Same as above + if (!('TransitionEvent' in window)) { + delete vendorPrefixes.transitionend.transition; + } +} + +/** + * Attempts to determine the correct vendor prefixed event name. + * + * @param {string} eventName + * @returns {string} + */ +function getVendorPrefixedEventName(eventName) { + if (prefixedEventNames[eventName]) { + return prefixedEventNames[eventName]; + } else if (!vendorPrefixes[eventName]) { + return eventName; + } + + var prefixMap = vendorPrefixes[eventName]; + + for (var styleProp in prefixMap) { + if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { + return prefixedEventNames[eventName] = prefixMap[styleProp]; + } + } + + return eventName; +} + +/** + * To identify top level events in ReactDOM, we use constants defined by this + * module. This is the only module that uses the unsafe* methods to express + * that the constants actually correspond to the browser event names. This lets + * us save some bundle size by avoiding a top level type -> event name map. + * The rest of ReactDOM code should import top level types from this file. + */ +var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort'); +var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend')); +var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration')); +var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart')); +var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur'); +var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay'); +var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough'); +var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel'); +var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change'); +var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click'); +var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close'); +var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend'); +var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart'); +var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate'); +var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu'); +var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy'); +var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut'); +var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick'); +var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick'); +var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag'); +var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend'); +var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter'); +var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit'); +var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave'); +var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover'); +var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart'); +var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop'); +var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange'); +var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied'); +var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted'); +var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended'); +var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error'); +var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus'); +var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture'); +var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input'); +var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid'); +var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown'); +var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress'); +var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup'); +var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load'); +var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart'); +var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata'); +var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata'); +var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture'); +var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown'); +var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove'); +var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout'); +var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover'); +var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup'); +var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste'); +var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause'); +var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play'); +var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing'); +var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel'); +var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown'); + + +var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove'); +var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout'); +var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover'); +var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup'); +var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress'); +var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange'); +var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset'); +var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll'); +var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked'); +var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking'); +var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange'); +var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled'); +var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit'); +var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend'); +var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput'); +var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate'); +var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle'); +var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel'); +var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend'); +var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove'); +var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart'); +var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend')); +var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange'); +var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting'); +var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel'); + +// List of events that need to be individually attached to media elements. +// Note that events in this list will *not* be listened to at the top level +// unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`. +var mediaEventTypes = [TOP_ABORT, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_VOLUME_CHANGE, TOP_WAITING]; + +function getRawEventName(topLevelType) { + return unsafeCastDOMTopLevelTypeToString(topLevelType); +} + +/** + * These variables store information about text content of a target node, + * allowing comparison of content before and after a given event. + * + * Identify the node where selection currently begins, then observe + * both its text content and its current position in the DOM. Since the + * browser may natively replace the target node during composition, we can + * use its position to find its replacement. + * + * + */ + +var root = null; +var startText = null; +var fallbackText = null; + +function initialize(nativeEventTarget) { + root = nativeEventTarget; + startText = getText(); + return true; +} + +function reset() { + root = null; + startText = null; + fallbackText = null; +} + +function getData() { + if (fallbackText) { + return fallbackText; + } + + var start = void 0; + var startValue = startText; + var startLength = startValue.length; + var end = void 0; + var endValue = getText(); + var endLength = endValue.length; + + for (start = 0; start < startLength; start++) { + if (startValue[start] !== endValue[start]) { + break; + } + } + + var minEnd = startLength - start; + for (end = 1; end <= minEnd; end++) { + if (startValue[startLength - end] !== endValue[endLength - end]) { + break; + } + } + + var sliceTail = end > 1 ? 1 - end : undefined; + fallbackText = endValue.slice(start, sliceTail); + return fallbackText; +} + +function getText() { + if ('value' in root) { + return root.value; + } + return root.textContent; +} + +/* eslint valid-typeof: 0 */ + +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function () { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} + +function functionThatReturnsFalse() { + return false; +} + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === 'target') { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} + +_assign(SyntheticEvent.prototype, { + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== 'unknown') { + event.returnValue = false; + } + this.isDefaultPrevented = functionThatReturnsTrue; + }, + + stopPropagation: function () { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== 'unknown') { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = functionThatReturnsTrue; + }, + + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + this.isPersistent = functionThatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function () { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName])); + } + } + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null)); + Object.defineProperty(this, 'isDefaultPrevented', getPooledWarningPropertyDefinition('isDefaultPrevented', functionThatReturnsFalse)); + Object.defineProperty(this, 'isPropagationStopped', getPooledWarningPropertyDefinition('isPropagationStopped', functionThatReturnsFalse)); + Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', function () {})); + Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', function () {})); + } + } +}); + +SyntheticEvent.Interface = EventInterface; + +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function (Interface) { + var Super = this; + + var E = function () {}; + E.prototype = Super.prototype; + var prototype = new E(); + + function Class() { + return Super.apply(this, arguments); + } + _assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = _assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; +}; + +addEventPoolingTo(SyntheticEvent); + +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === 'function'; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? 'setting the method' : 'setting the property'; + warn(action, 'This is effectively a no-op'); + return val; + } + + function get() { + var action = isFunction ? 'accessing the method' : 'accessing the property'; + var result = isFunction ? 'This is a no-op function' : 'This is set to null'; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + !warningCondition ? warningWithoutStack$1(false, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + 'If you must keep the original synthetic event around, use event.persist(). ' + 'See https://fb.me/react-event-pooling for more information.', action, propName, result) : void 0; + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + !(event instanceof EventConstructor) ? invariant(false, 'Trying to release an event instance into a pool of a different type.') : void 0; + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ +var SyntheticCompositionEvent = SyntheticEvent.extend({ + data: null +}); + +/** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ +var SyntheticInputEvent = SyntheticEvent.extend({ + data: null +}); + +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +var START_KEYCODE = 229; + +var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window; + +var documentMode = null; +if (canUseDOM && 'documentMode' in document) { + documentMode = document.documentMode; +} + +// Webkit offers a very useful `textInput` event that can be used to +// directly represent `beforeInput`. The IE `textinput` event is not as +// useful, so we don't use it. +var canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode; + +// In IE9+, we have access to composition events, but the data supplied +// by the native compositionend event may be incorrect. Japanese ideographic +// spaces, for instance (\u3000) are not recorded correctly. +var useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11); + +var SPACEBAR_CODE = 32; +var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + +// Events and their corresponding property names. +var eventTypes = { + beforeInput: { + phasedRegistrationNames: { + bubbled: 'onBeforeInput', + captured: 'onBeforeInputCapture' + }, + dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE] + }, + compositionEnd: { + phasedRegistrationNames: { + bubbled: 'onCompositionEnd', + captured: 'onCompositionEndCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_END, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] + }, + compositionStart: { + phasedRegistrationNames: { + bubbled: 'onCompositionStart', + captured: 'onCompositionStartCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] + }, + compositionUpdate: { + phasedRegistrationNames: { + bubbled: 'onCompositionUpdate', + captured: 'onCompositionUpdateCapture' + }, + dependencies: [TOP_BLUR, TOP_COMPOSITION_UPDATE, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN] + } +}; + +// Track whether we've ever handled a keypress on the space key. +var hasSpaceKeypress = false; + +/** + * Return whether a native keypress event is assumed to be a command. + * This is required because Firefox fires `keypress` events for key commands + * (cut, copy, select-all, etc.) even though no character is inserted. + */ +function isKeypressCommand(nativeEvent) { + return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && + // ctrlKey && altKey is equivalent to AltGr, and is not a command. + !(nativeEvent.ctrlKey && nativeEvent.altKey); +} + +/** + * Translate native top level events into event types. + * + * @param {string} topLevelType + * @return {object} + */ +function getCompositionEventType(topLevelType) { + switch (topLevelType) { + case TOP_COMPOSITION_START: + return eventTypes.compositionStart; + case TOP_COMPOSITION_END: + return eventTypes.compositionEnd; + case TOP_COMPOSITION_UPDATE: + return eventTypes.compositionUpdate; + } +} + +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionStart(topLevelType, nativeEvent) { + return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE; +} + +/** + * Does our fallback mode think that this event is the end of composition? + * + * @param {string} topLevelType + * @param {object} nativeEvent + * @return {boolean} + */ +function isFallbackCompositionEnd(topLevelType, nativeEvent) { + switch (topLevelType) { + case TOP_KEY_UP: + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; + case TOP_KEY_DOWN: + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; + case TOP_KEY_PRESS: + case TOP_MOUSE_DOWN: + case TOP_BLUR: + // Events are not possible without cancelling IME. + return true; + default: + return false; + } +} + +/** + * Google Input Tools provides composition data via a CustomEvent, + * with the `data` property populated in the `detail` object. If this + * is available on the event object, use it. If not, this is a plain + * composition event and we have nothing special to extract. + * + * @param {object} nativeEvent + * @return {?string} + */ +function getDataFromCustomEvent(nativeEvent) { + var detail = nativeEvent.detail; + if (typeof detail === 'object' && 'data' in detail) { + return detail.data; + } + return null; +} + +/** + * Check if a composition event was triggered by Korean IME. + * Our fallback mode does not work well with IE's Korean IME, + * so just use native composition events when Korean IME is used. + * Although CompositionEvent.locale property is deprecated, + * it is available in IE, where our fallback mode is enabled. + * + * @param {object} nativeEvent + * @return {boolean} + */ +function isUsingKoreanIME(nativeEvent) { + return nativeEvent.locale === 'ko'; +} + +// Track the current IME composition status, if any. +var isComposing = false; + +/** + * @return {?object} A SyntheticCompositionEvent. + */ +function extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var eventType = void 0; + var fallbackData = void 0; + + if (canUseCompositionEvent) { + eventType = getCompositionEventType(topLevelType); + } else if (!isComposing) { + if (isFallbackCompositionStart(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionStart; + } + } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) { + eventType = eventTypes.compositionEnd; + } + + if (!eventType) { + return null; + } + + if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!isComposing && eventType === eventTypes.compositionStart) { + isComposing = initialize(nativeEventTarget); + } else if (eventType === eventTypes.compositionEnd) { + if (isComposing) { + fallbackData = getData(); + } + } + } + + var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget); + + if (fallbackData) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + event.data = fallbackData; + } else { + var customData = getDataFromCustomEvent(nativeEvent); + if (customData !== null) { + event.data = customData; + } + } + + accumulateTwoPhaseDispatches(event); + return event; +} + +/** + * @param {TopLevelType} topLevelType Number from `TopLevelType`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The string corresponding to this `beforeInput` event. + */ +function getNativeBeforeInputChars(topLevelType, nativeEvent) { + switch (topLevelType) { + case TOP_COMPOSITION_END: + return getDataFromCustomEvent(nativeEvent); + case TOP_KEY_PRESS: + /** + * If native `textInput` events are available, our goal is to make + * use of them. However, there is a special case: the spacebar key. + * In Webkit, preventing default on a spacebar `textInput` event + * cancels character insertion, but it *also* causes the browser + * to fall back to its default spacebar behavior of scrolling the + * page. + * + * Tracking at: + * https://code.google.com/p/chromium/issues/detail?id=355103 + * + * To avoid this issue, use the keypress event as if no `textInput` + * event is available. + */ + var which = nativeEvent.which; + if (which !== SPACEBAR_CODE) { + return null; + } + + hasSpaceKeypress = true; + return SPACEBAR_CHAR; + + case TOP_TEXT_INPUT: + // Record the characters to be added to the DOM. + var chars = nativeEvent.data; + + // If it's a spacebar character, assume that we have already handled + // it at the keypress level and bail immediately. Android Chrome + // doesn't give us keycodes, so we need to ignore it. + if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { + return null; + } + + return chars; + + default: + // For other native event types, do nothing. + return null; + } +} + +/** + * For browsers that do not provide the `textInput` event, extract the + * appropriate string to use for SyntheticInputEvent. + * + * @param {number} topLevelType Number from `TopLevelEventTypes`. + * @param {object} nativeEvent Native browser event. + * @return {?string} The fallback string for this `beforeInput` event. + */ +function getFallbackBeforeInputChars(topLevelType, nativeEvent) { + // If we are currently composing (IME) and using a fallback to do so, + // try to extract the composed characters from the fallback object. + // If composition event is available, we extract a string only at + // compositionevent, otherwise extract it at fallback events. + if (isComposing) { + if (topLevelType === TOP_COMPOSITION_END || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) { + var chars = getData(); + reset(); + isComposing = false; + return chars; + } + return null; + } + + switch (topLevelType) { + case TOP_PASTE: + // If a paste event occurs after a keypress, throw out the input + // chars. Paste events should not lead to BeforeInput events. + return null; + case TOP_KEY_PRESS: + /** + * As of v27, Firefox may fire keypress events even when no character + * will be inserted. A few possibilities: + * + * - `which` is `0`. Arrow keys, Esc key, etc. + * + * - `which` is the pressed key code, but no char is available. + * Ex: 'AltGr + d` in Polish. There is no modified character for + * this key combination and no character is inserted into the + * document, but FF fires the keypress for char code `100` anyway. + * No `input` event will occur. + * + * - `which` is the pressed key code, but a command combination is + * being used. Ex: `Cmd+C`. No character is inserted, and no + * `input` event will occur. + */ + if (!isKeypressCommand(nativeEvent)) { + // IE fires the `keypress` event when a user types an emoji via + // Touch keyboard of Windows. In such a case, the `char` property + // holds an emoji character like `\uD83D\uDE0A`. Because its length + // is 2, the property `which` does not represent an emoji correctly. + // In such a case, we directly return the `char` property instead of + // using `which`. + if (nativeEvent.char && nativeEvent.char.length > 1) { + return nativeEvent.char; + } else if (nativeEvent.which) { + return String.fromCharCode(nativeEvent.which); + } + } + return null; + case TOP_COMPOSITION_END: + return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data; + default: + return null; + } +} + +/** + * Extract a SyntheticInputEvent for `beforeInput`, based on either native + * `textInput` or fallback behavior. + * + * @return {?object} A SyntheticInputEvent. + */ +function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var chars = void 0; + + if (canUseTextInputEvent) { + chars = getNativeBeforeInputChars(topLevelType, nativeEvent); + } else { + chars = getFallbackBeforeInputChars(topLevelType, nativeEvent); + } + + // If no characters are being inserted, no BeforeInput event should + // be fired. + if (!chars) { + return null; + } + + var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget); + + event.data = chars; + accumulateTwoPhaseDispatches(event); + return event; +} + +/** + * Create an `onBeforeInput` event to match + * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. + * + * This event plugin is based on the native `textInput` event + * available in Chrome, Safari, Opera, and IE. This event fires after + * `onKeyPress` and `onCompositionEnd`, but before `onInput`. + * + * `beforeInput` is spec'd but not implemented in any browsers, and + * the `input` event does not provide any useful information about what has + * actually been added, contrary to the spec. Thus, `textInput` is the best + * available event to identify the characters that have actually been inserted + * into the target node. + * + * This plugin is also responsible for emitting `composition` events, thus + * allowing us to share composition fallback code for both `beforeInput` and + * `composition` event types. + */ +var BeforeInputEventPlugin = { + eventTypes: eventTypes, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var composition = extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); + + var beforeInput = extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget); + + if (composition === null) { + return beforeInput; + } + + if (beforeInput === null) { + return composition; + } + + return [composition, beforeInput]; + } +}; + +// Use to restore controlled state after a change event has fired. + +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + !(typeof restoreImpl === 'function') ? invariant(false, 'setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0; + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} + +function setRestoreImplementation(impl) { + restoreImpl = impl; +} + +function enqueueStateRestore(target) { + if (restoreTarget) { + if (restoreQueue) { + restoreQueue.push(target); + } else { + restoreQueue = [target]; + } + } else { + restoreTarget = target; + } +} + +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var _batchedUpdatesImpl = function (fn, bookkeeping) { + return fn(bookkeeping); +}; +var _interactiveUpdatesImpl = function (fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdatesImpl = function () {}; + +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); + } + } +} + +function interactiveUpdates(fn, a, b) { + return _interactiveUpdatesImpl(fn, a, b); +} + + + +function setBatchingImplementation(batchedUpdatesImpl, interactiveUpdatesImpl, flushInteractiveUpdatesImpl) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _interactiveUpdatesImpl = interactiveUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} + +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + color: true, + date: true, + datetime: true, + 'datetime-local': true, + email: true, + month: true, + number: true, + password: true, + range: true, + search: true, + tel: true, + text: true, + time: true, + url: true, + week: true +}; + +function isTextInputElement(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + + if (nodeName === 'input') { + return !!supportedInputTypes[elem.type]; + } + + if (nodeName === 'textarea') { + return true; + } + + return false; +} + +/** + * HTML nodeType values that represent the type of the node + */ + +var ELEMENT_NODE = 1; +var TEXT_NODE = 3; +var COMMENT_NODE = 8; +var DOCUMENT_NODE = 9; +var DOCUMENT_FRAGMENT_NODE = 11; + +/** + * Gets the target node from a native browser event by accounting for + * inconsistencies in browser DOM APIs. + * + * @param {object} nativeEvent Native browser event. + * @return {DOMEventTarget} Target node. + */ +function getEventTarget(nativeEvent) { + // Fallback to nativeEvent.srcElement for IE9 + // https://github.com/facebook/react/issues/12506 + var target = nativeEvent.target || nativeEvent.srcElement || window; + + // Normalize SVG element events #4963 + if (target.correspondingUseElement) { + target = target.correspondingUseElement; + } + + // Safari may fire events on text nodes (Node.TEXT_NODE is 3). + // @see http://www.quirksmode.org/js/events_properties.html + return target.nodeType === TEXT_NODE ? target.parentNode : target; +} + +/** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ +function isEventSupported(eventNameSuffix) { + if (!canUseDOM) { + return false; + } + + var eventName = 'on' + eventNameSuffix; + var isSupported = eventName in document; + + if (!isSupported) { + var element = document.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof element[eventName] === 'function'; + } + + return isSupported; +} + +function isCheckable(elem) { + var type = elem.type; + var nodeName = elem.nodeName; + return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio'); +} + +function getTracker(node) { + return node._valueTracker; +} + +function detachTracker(node) { + node._valueTracker = null; +} + +function getValueFromNode(node) { + var value = ''; + if (!node) { + return value; + } + + if (isCheckable(node)) { + value = node.checked ? 'true' : 'false'; + } else { + value = node.value; + } + + return value; +} + +function trackValueOnNode(node) { + var valueField = isCheckable(node) ? 'checked' : 'value'; + var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField); + + var currentValue = '' + node[valueField]; + + // if someone has already defined a value or Safari, then bail + // and don't track value will cause over reporting of changes, + // but it's better then a hard failure + // (needed for certain tests that spyOn input values and Safari) + if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') { + return; + } + var get = descriptor.get, + set = descriptor.set; + + Object.defineProperty(node, valueField, { + configurable: true, + get: function () { + return get.call(this); + }, + set: function (value) { + currentValue = '' + value; + set.call(this, value); + } + }); + // We could've passed this the first time + // but it triggers a bug in IE11 and Edge 14/15. + // Calling defineProperty() again should be equivalent. + // https://github.com/facebook/react/issues/11768 + Object.defineProperty(node, valueField, { + enumerable: descriptor.enumerable + }); + + var tracker = { + getValue: function () { + return currentValue; + }, + setValue: function (value) { + currentValue = '' + value; + }, + stopTracking: function () { + detachTracker(node); + delete node[valueField]; + } + }; + return tracker; +} + +function track(node) { + if (getTracker(node)) { + return; + } + + // TODO: Once it's just Fiber we can move this to node._wrapperState + node._valueTracker = trackValueOnNode(node); +} + +function updateValueIfChanged(node) { + if (!node) { + return false; + } + + var tracker = getTracker(node); + // if there is no tracker at this point it's unlikely + // that trying again will succeed + if (!tracker) { + return true; + } + + var lastValue = tracker.getValue(); + var nextValue = getValueFromNode(node); + if (nextValue !== lastValue) { + tracker.setValue(nextValue); + return true; + } + return false; +} + +var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function (name, source, ownerName) { + var sourceInfo = ''; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ''); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ''); + fileName = folderName + '/' + fileName; + } + } + } + } + sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; + } else if (ownerName) { + sourceInfo = ' (created by ' + ownerName + ')'; + } + return '\n in ' + (name || 'Unknown') + sourceInfo; +}; + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === 'function' && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; + } + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ''; + return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === 'number') { + warningWithoutStack$1(false, 'Received an unexpected object in getComponentName(). ' + 'This is likely a bug in React. Please file an issue.'); + } + } + if (typeof type === 'function') { + return type.displayName || type.name || null; + } + if (typeof type === 'string') { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return 'ConcurrentMode'; + case REACT_FRAGMENT_TYPE: + return 'Fragment'; + case REACT_PORTAL_TYPE: + return 'Portal'; + case REACT_PROFILER_TYPE: + return 'Profiler'; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + case REACT_SUSPENSE_TYPE: + return 'Suspense'; + } + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return 'Context.Consumer'; + case REACT_PROVIDER_TYPE: + return 'Context.Provider'; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, 'ForwardRef'); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + } + } + } + return null; +} + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ''; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ''; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var current = null; +var phase = null; + +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== 'undefined') { + return getComponentName(owner.type); + } + } + return null; +} + +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ''; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); + } + return ''; +} + +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; + } +} + +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; + } +} + +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = warningWithoutStack$1; + +{ + warning = function (condition, format) { + if (condition) { + return; + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args + + for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; + } + + warningWithoutStack$1.apply(undefined, [false, format + '%s'].concat(args, [stack])); + }; +} + +var warning$1 = warning; + +// A reserved attribute. +// It is handled by React separately and shouldn't be written to the DOM. +var RESERVED = 0; + +// A simple string attribute. +// Attributes that aren't in the whitelist are presumed to have this type. +var STRING = 1; + +// A string attribute that accepts booleans in React. In HTML, these are called +// "enumerated" attributes with "true" and "false" as possible values. +// When true, it should be set to a "true" string. +// When false, it should be set to a "false" string. +var BOOLEANISH_STRING = 2; + +// A real boolean attribute. +// When true, it should be present (set either to an empty string or its name). +// When false, it should be omitted. +var BOOLEAN = 3; + +// An attribute that can be used as a flag as well as with a value. +// When true, it should be present (set either to an empty string or its name). +// When false, it should be omitted. +// For any other value, should be present with that value. +var OVERLOADED_BOOLEAN = 4; + +// An attribute that must be numeric or parse as a numeric. +// When falsy, it should be removed. +var NUMERIC = 5; + +// An attribute that must be positive numeric or parse as a positive numeric. +// When falsy, it should be removed. +var POSITIVE_NUMERIC = 6; + +/* eslint-disable max-len */ +var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD'; +/* eslint-enable max-len */ +var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040'; + + +var ROOT_ATTRIBUTE_NAME = 'data-reactroot'; +var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$'); + +var hasOwnProperty = Object.prototype.hasOwnProperty; +var illegalAttributeNameCache = {}; +var validatedAttributeNameCache = {}; + +function isAttributeNameSafe(attributeName) { + if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { + return true; + } + if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { + return false; + } + if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { + validatedAttributeNameCache[attributeName] = true; + return true; + } + illegalAttributeNameCache[attributeName] = true; + { + warning$1(false, 'Invalid attribute name: `%s`', attributeName); + } + return false; +} + +function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) { + if (propertyInfo !== null) { + return propertyInfo.type === RESERVED; + } + if (isCustomComponentTag) { + return false; + } + if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) { + return true; + } + return false; +} + +function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) { + if (propertyInfo !== null && propertyInfo.type === RESERVED) { + return false; + } + switch (typeof value) { + case 'function': + // $FlowIssue symbol is perfectly valid here + case 'symbol': + // eslint-disable-line + return true; + case 'boolean': + { + if (isCustomComponentTag) { + return false; + } + if (propertyInfo !== null) { + return !propertyInfo.acceptsBooleans; + } else { + var prefix = name.toLowerCase().slice(0, 5); + return prefix !== 'data-' && prefix !== 'aria-'; + } + } + default: + return false; + } +} + +function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) { + if (value === null || typeof value === 'undefined') { + return true; + } + if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) { + return true; + } + if (isCustomComponentTag) { + return false; + } + if (propertyInfo !== null) { + switch (propertyInfo.type) { + case BOOLEAN: + return !value; + case OVERLOADED_BOOLEAN: + return value === false; + case NUMERIC: + return isNaN(value); + case POSITIVE_NUMERIC: + return isNaN(value) || value < 1; + } + } + return false; +} + +function getPropertyInfo(name) { + return properties.hasOwnProperty(name) ? properties[name] : null; +} + +function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace) { + this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN; + this.attributeName = attributeName; + this.attributeNamespace = attributeNamespace; + this.mustUseProperty = mustUseProperty; + this.propertyName = name; + this.type = type; +} + +// When adding attributes to this list, be sure to also add them to +// the `possibleStandardNames` module to ensure casing and incorrect +// name warnings. +var properties = {}; + +// These props are reserved by React. They shouldn't be written to the DOM. +['children', 'dangerouslySetInnerHTML', +// TODO: This prevents the assignment of defaultValue to regular +// elements (not just inputs). Now that ReactDOMInput assigns to the +// defaultValue property -- do we need this? +'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// A few React string attributes have a different name. +// This is a mapping from React prop names to the attribute names. +[['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) { + var name = _ref[0], + attributeName = _ref[1]; + + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, // attributeName + null); +} // attributeNamespace +); + +// These are "enumerated" HTML attributes that accept "true" and "false". +// In React, we let users pass `true` and `false` even though technically +// these aren't boolean attributes (they are coerced to strings). +['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +// These are "enumerated" SVG attributes that accept "true" and "false". +// In React, we let users pass `true` and `false` even though technically +// these aren't boolean attributes (they are coerced to strings). +// Since these are SVG attributes, their attribute names are case-sensitive. +['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML boolean attributes. +['allowFullScreen', 'async', +// Note: there is a special case that prevents it from being written to the DOM +// on the client side because the browsers are inconsistent. Instead we call focus(). +'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', +// Microdata +'itemScope'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +// These are the few React props that we set as DOM properties +// rather than attributes. These are all booleans. +['checked', +// Note: `option.selected` is not updated if `select.multiple` is +// disabled with `removeAttribute`. We have special logic for handling this. +'multiple', 'muted', 'selected'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that are "overloaded booleans": they behave like +// booleans, but can also accept a string value. +['capture', 'download'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that must be positive numbers. +['cols', 'rows', 'size', 'span'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty + name, // attributeName + null); +} // attributeNamespace +); + +// These are HTML attributes that must be numbers. +['rowSpan', 'start'].forEach(function (name) { + properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty + name.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +var CAMELIZE = /[\-\:]([a-z])/g; +var capitalize = function (token) { + return token[1].toUpperCase(); +}; + +// This is a list of all SVG attributes that need special casing, namespacing, +// or boolean value assignment. Regular attributes that just accept strings +// and have the same names are omitted, just like in the HTML whitelist. +// Some of these attributes can be hard to find. This list was created by +// scrapping the MDN documentation. +['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, null); +} // attributeNamespace +); + +// String SVG attributes with the xlink namespace. +['xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, 'http://www.w3.org/1999/xlink'); +}); + +// String SVG attributes with the xml namespace. +['xml:base', 'xml:lang', 'xml:space'].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); + properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty + attributeName, 'http://www.w3.org/XML/1998/namespace'); +}); + +// These attribute exists both in HTML and SVG. +// The attribute name is case-sensitive in SVG so we can't just use +// the React name like we do for attributes that exist only in HTML. +['tabIndex', 'crossOrigin'].forEach(function (attributeName) { + properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty + attributeName.toLowerCase(), // attributeName + null); +} // attributeNamespace +); + +/** + * Get the value for a property on a node. Only used in DEV for SSR validation. + * The "expected" argument is used as a hint of what the expected value is. + * Some properties have multiple equivalent values. + */ +function getValueForProperty(node, name, expected, propertyInfo) { + { + if (propertyInfo.mustUseProperty) { + var propertyName = propertyInfo.propertyName; + + return node[propertyName]; + } else { + var attributeName = propertyInfo.attributeName; + + var stringValue = null; + + if (propertyInfo.type === OVERLOADED_BOOLEAN) { + if (node.hasAttribute(attributeName)) { + var value = node.getAttribute(attributeName); + if (value === '') { + return true; + } + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + return value; + } + if (value === '' + expected) { + return expected; + } + return value; + } + } else if (node.hasAttribute(attributeName)) { + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return node.getAttribute(attributeName); + } + if (propertyInfo.type === BOOLEAN) { + // If this was a boolean, it doesn't matter what the value is + // the fact that we have it is the same as the expected. + return expected; + } + // Even if this property uses a namespace we use getAttribute + // because we assume its namespaced name is the same as our config. + // To use getAttributeNS we need the local name which we don't have + // in our config atm. + stringValue = node.getAttribute(attributeName); + } + + if (shouldRemoveAttribute(name, expected, propertyInfo, false)) { + return stringValue === null ? expected : stringValue; + } else if (stringValue === '' + expected) { + return expected; + } else { + return stringValue; + } + } + } +} + +/** + * Get the value for a attribute on a node. Only used in DEV for SSR validation. + * The third argument is used as a hint of what the expected value is. Some + * attributes have multiple equivalent values. + */ +function getValueForAttribute(node, name, expected) { + { + if (!isAttributeNameSafe(name)) { + return; + } + if (!node.hasAttribute(name)) { + return expected === undefined ? undefined : null; + } + var value = node.getAttribute(name); + if (value === '' + expected) { + return expected; + } + return value; + } +} + +/** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ +function setValueForProperty(node, name, value, isCustomComponentTag) { + var propertyInfo = getPropertyInfo(name); + if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) { + return; + } + if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) { + value = null; + } + // If the prop isn't in the special list, treat it as a simple attribute. + if (isCustomComponentTag || propertyInfo === null) { + if (isAttributeNameSafe(name)) { + var _attributeName = name; + if (value === null) { + node.removeAttribute(_attributeName); + } else { + node.setAttribute(_attributeName, '' + value); + } + } + return; + } + var mustUseProperty = propertyInfo.mustUseProperty; + + if (mustUseProperty) { + var propertyName = propertyInfo.propertyName; + + if (value === null) { + var type = propertyInfo.type; + + node[propertyName] = type === BOOLEAN ? false : ''; + } else { + // Contrary to `setAttribute`, object properties are properly + // `toString`ed by IE8/9. + node[propertyName] = value; + } + return; + } + // The rest are treated as attributes with special cases. + var attributeName = propertyInfo.attributeName, + attributeNamespace = propertyInfo.attributeNamespace; + + if (value === null) { + node.removeAttribute(attributeName); + } else { + var _type = propertyInfo.type; + + var attributeValue = void 0; + if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) { + attributeValue = ''; + } else { + // `setAttribute` with objects becomes only `[object]` in IE8/9, + // ('' + value) makes it output the correct toString()-value. + attributeValue = '' + value; + } + if (attributeNamespace) { + node.setAttributeNS(attributeNamespace, attributeName, attributeValue); + } else { + node.setAttribute(attributeName, attributeValue); + } + } +} + +// Flow does not allow string concatenation of most non-string types. To work +// around this limitation, we use an opaque type that can only be obtained by +// passing the value through getToStringValue first. +function toString(value) { + return '' + value; +} + +function getToStringValue(value) { + switch (typeof value) { + case 'boolean': + case 'number': + case 'object': + case 'string': + case 'undefined': + return value; + default: + // function, symbol are assigned as empty strings + return ''; + } +} + +var ReactDebugCurrentFrame$1 = null; + +var ReactControlledValuePropTypes = { + checkPropTypes: null +}; + +{ + ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; + + var hasReadOnlyValue = { + button: true, + checkbox: true, + image: true, + hidden: true, + radio: true, + reset: true, + submit: true + }; + + var propTypes = { + value: function (props, propName, componentName) { + if (hasReadOnlyValue[props.type] || props.onChange || props.readOnly || props.disabled || props[propName] == null) { + return null; + } + return new Error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); + }, + checked: function (props, propName, componentName) { + if (props.onChange || props.readOnly || props.disabled || props[propName] == null) { + return null; + } + return new Error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.'); + } + }; + + /** + * Provide a linked `value` attribute for controlled forms. You should not use + * this outside of the ReactDOM controlled form components. + */ + ReactControlledValuePropTypes.checkPropTypes = function (tagName, props) { + checkPropTypes(propTypes, props, 'prop', tagName, ReactDebugCurrentFrame$1.getStackAddendum); + }; +} + +var enableUserTimingAPI = true; + +// Helps identify side effects in begin-phase lifecycle hooks and setState reducers: +var debugRenderPhaseSideEffects = false; + +// In some cases, StrictMode should also double-render lifecycles. +// This can be confusing for tests though, +// And it can be bad for performance in production. +// This feature flag can be used to control the behavior: +var debugRenderPhaseSideEffectsForStrictMode = true; + +// To preserve the "Pause on caught exceptions" behavior of the debugger, we +// replay the begin phase of a failed component inside invokeGuardedCallback. +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; + +// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6: +var warnAboutDeprecatedLifecycles = false; + +// Gather advanced timing metrics for Profiler subtrees. +var enableProfilerTimer = true; + +// Trace which interactions trigger each commit. +var enableSchedulerTracing = true; + +// Only used in www builds. +var enableSuspenseServerRenderer = false; // TODO: true? Here it might just be false. + +// Only used in www builds. + + +// Only used in www builds. + + +// React Fire: prevent the value and checked attributes from syncing +// with their related DOM properties +var disableInputAttributeSyncing = false; + +// These APIs will no longer be "unstable" in the upcoming 16.7 release, +// Control this behavior with a flag to support 16.6 minor releases in the meanwhile. +var enableStableConcurrentModeAPIs = false; + +var warnAboutShorthandPropertyCollision = false; + +// TODO: direct imports like some-package/src/* are bad. Fix me. +var didWarnValueDefaultValue = false; +var didWarnCheckedDefaultChecked = false; +var didWarnControlledToUncontrolled = false; +var didWarnUncontrolledToControlled = false; + +function isControlled(props) { + var usesChecked = props.type === 'checkbox' || props.type === 'radio'; + return usesChecked ? props.checked != null : props.value != null; +} + +/** + * Implements an host component that allows setting these optional + * props: `checked`, `value`, `defaultChecked`, and `defaultValue`. + * + * If `checked` or `value` are not supplied (or null/undefined), user actions + * that affect the checked state or value will trigger updates to the element. + * + * If they are supplied (and not null/undefined), the rendered element will not + * trigger updates to the element. Instead, the props must change in order for + * the rendered element to be updated. + * + * The rendered element will be initialized as unchecked (or `defaultChecked`) + * with an empty value (or `defaultValue`). + * + * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html + */ + +function getHostProps(element, props) { + var node = element; + var checked = props.checked; + + var hostProps = _assign({}, props, { + defaultChecked: undefined, + defaultValue: undefined, + value: undefined, + checked: checked != null ? checked : node._wrapperState.initialChecked + }); + + return hostProps; +} + +function initWrapperState(element, props) { + { + ReactControlledValuePropTypes.checkPropTypes('input', props); + + if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { + warning$1(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); + didWarnCheckedDefaultChecked = true; + } + if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { + warning$1(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type); + didWarnValueDefaultValue = true; + } + } + + var node = element; + var defaultValue = props.defaultValue == null ? '' : props.defaultValue; + + node._wrapperState = { + initialChecked: props.checked != null ? props.checked : props.defaultChecked, + initialValue: getToStringValue(props.value != null ? props.value : defaultValue), + controlled: isControlled(props) + }; +} + +function updateChecked(element, props) { + var node = element; + var checked = props.checked; + if (checked != null) { + setValueForProperty(node, 'checked', checked, false); + } +} + +function updateWrapper(element, props) { + var node = element; + { + var _controlled = isControlled(props); + + if (!node._wrapperState.controlled && _controlled && !didWarnUncontrolledToControlled) { + warning$1(false, 'A component is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); + didWarnUncontrolledToControlled = true; + } + if (node._wrapperState.controlled && !_controlled && !didWarnControlledToUncontrolled) { + warning$1(false, 'A component is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', props.type); + didWarnControlledToUncontrolled = true; + } + } + + updateChecked(element, props); + + var value = getToStringValue(props.value); + var type = props.type; + + if (value != null) { + if (type === 'number') { + if (value === 0 && node.value === '' || + // We explicitly want to coerce to number here if possible. + // eslint-disable-next-line + node.value != value) { + node.value = toString(value); + } + } else if (node.value !== toString(value)) { + node.value = toString(value); + } + } else if (type === 'submit' || type === 'reset') { + // Submit/reset inputs need the attribute removed completely to avoid + // blank-text buttons. + node.removeAttribute('value'); + return; + } + + if (disableInputAttributeSyncing) { + // When not syncing the value attribute, React only assigns a new value + // whenever the defaultValue React prop has changed. When not present, + // React does nothing + if (props.hasOwnProperty('defaultValue')) { + setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); + } + } else { + // When syncing the value attribute, the value comes from a cascade of + // properties: + // 1. The value React property + // 2. The defaultValue React property + // 3. Otherwise there should be no change + if (props.hasOwnProperty('value')) { + setDefaultValue(node, props.type, value); + } else if (props.hasOwnProperty('defaultValue')) { + setDefaultValue(node, props.type, getToStringValue(props.defaultValue)); + } + } + + if (disableInputAttributeSyncing) { + // When not syncing the checked attribute, the attribute is directly + // controllable from the defaultValue React property. It needs to be + // updated as new props come in. + if (props.defaultChecked == null) { + node.removeAttribute('checked'); + } else { + node.defaultChecked = !!props.defaultChecked; + } + } else { + // When syncing the checked attribute, it only changes when it needs + // to be removed, such as transitioning from a checkbox into a text input + if (props.checked == null && props.defaultChecked != null) { + node.defaultChecked = !!props.defaultChecked; + } + } +} + +function postMountWrapper(element, props, isHydrating) { + var node = element; + + // Do not assign value if it is already set. This prevents user text input + // from being lost during SSR hydration. + if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) { + var type = props.type; + var isButton = type === 'submit' || type === 'reset'; + + // Avoid setting value attribute on submit/reset inputs as it overrides the + // default value provided by the browser. See: #12872 + if (isButton && (props.value === undefined || props.value === null)) { + return; + } + + var _initialValue = toString(node._wrapperState.initialValue); + + // Do not assign value if it is already set. This prevents user text input + // from being lost during SSR hydration. + if (!isHydrating) { + if (disableInputAttributeSyncing) { + var value = getToStringValue(props.value); + + // When not syncing the value attribute, the value property points + // directly to the React prop. Only assign it if it exists. + if (value != null) { + // Always assign on buttons so that it is possible to assign an + // empty string to clear button text. + // + // Otherwise, do not re-assign the value property if is empty. This + // potentially avoids a DOM write and prevents Firefox (~60.0.1) from + // prematurely marking required inputs as invalid. Equality is compared + // to the current value in case the browser provided value is not an + // empty string. + if (isButton || value !== node.value) { + node.value = toString(value); + } + } + } else { + // When syncing the value attribute, the value property should use + // the wrapperState._initialValue property. This uses: + // + // 1. The value React property when present + // 2. The defaultValue React property when present + // 3. An empty string + if (_initialValue !== node.value) { + node.value = _initialValue; + } + } + } + + if (disableInputAttributeSyncing) { + // When not syncing the value attribute, assign the value attribute + // directly from the defaultValue React property (when present) + var defaultValue = getToStringValue(props.defaultValue); + if (defaultValue != null) { + node.defaultValue = toString(defaultValue); + } + } else { + // Otherwise, the value attribute is synchronized to the property, + // so we assign defaultValue to the same thing as the value property + // assignment step above. + node.defaultValue = _initialValue; + } + } + + // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug + // this is needed to work around a chrome bug where setting defaultChecked + // will sometimes influence the value of checked (even after detachment). + // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 + // We need to temporarily unset name to avoid disrupting radio button groups. + var name = node.name; + if (name !== '') { + node.name = ''; + } + + if (disableInputAttributeSyncing) { + // When not syncing the checked attribute, the checked property + // never gets assigned. It must be manually set. We don't want + // to do this when hydrating so that existing user input isn't + // modified + if (!isHydrating) { + updateChecked(element, props); + } + + // Only assign the checked attribute if it is defined. This saves + // a DOM write when controlling the checked attribute isn't needed + // (text inputs, submit/reset) + if (props.hasOwnProperty('defaultChecked')) { + node.defaultChecked = !node.defaultChecked; + node.defaultChecked = !!props.defaultChecked; + } + } else { + // When syncing the checked attribute, both the checked property and + // attribute are assigned at the same time using defaultChecked. This uses: + // + // 1. The checked React property when present + // 2. The defaultChecked React property when present + // 3. Otherwise, false + node.defaultChecked = !node.defaultChecked; + node.defaultChecked = !!node._wrapperState.initialChecked; + } + + if (name !== '') { + node.name = name; + } +} + +function restoreControlledState(element, props) { + var node = element; + updateWrapper(node, props); + updateNamedCousins(node, props); +} + +function updateNamedCousins(rootNode, props) { + var name = props.name; + if (props.type === 'radio' && name != null) { + var queryRoot = rootNode; + + while (queryRoot.parentNode) { + queryRoot = queryRoot.parentNode; + } + + // If `rootNode.form` was non-null, then we could try `form.elements`, + // but that sometimes behaves strangely in IE8. We could also try using + // `form.getElementsByName`, but that will only return direct children + // and won't include inputs that use the HTML5 `form=` attribute. Since + // the input might not even be in a form. It might not even be in the + // document. Let's just use the local `querySelectorAll` to ensure we don't + // miss anything. + var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]'); + + for (var i = 0; i < group.length; i++) { + var otherNode = group[i]; + if (otherNode === rootNode || otherNode.form !== rootNode.form) { + continue; + } + // This will throw if radio buttons rendered by different copies of React + // and the same name are rendered into the same form (same as #1939). + // That's probably okay; we don't support it just as we don't support + // mixing React radio buttons with non-React ones. + var otherProps = getFiberCurrentPropsFromNode$1(otherNode); + !otherProps ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.') : void 0; + + // We need update the tracked value on the named cousin since the value + // was changed but the input saw no event or value set + updateValueIfChanged(otherNode); + + // If this is a controlled radio button group, forcing the input that + // was previously checked to update will cause it to be come re-checked + // as appropriate. + updateWrapper(otherNode, otherProps); + } + } +} + +// In Chrome, assigning defaultValue to certain input types triggers input validation. +// For number inputs, the display value loses trailing decimal points. For email inputs, +// Chrome raises "The specified value is not a valid email address". +// +// Here we check to see if the defaultValue has actually changed, avoiding these problems +// when the user is inputting text +// +// https://github.com/facebook/react/issues/7253 +function setDefaultValue(node, type, value) { + if ( + // Focused number inputs synchronize on blur. See ChangeEventPlugin.js + type !== 'number' || node.ownerDocument.activeElement !== node) { + if (value == null) { + node.defaultValue = toString(node._wrapperState.initialValue); + } else if (node.defaultValue !== toString(value)) { + node.defaultValue = toString(value); + } + } +} + +var eventTypes$1 = { + change: { + phasedRegistrationNames: { + bubbled: 'onChange', + captured: 'onChangeCapture' + }, + dependencies: [TOP_BLUR, TOP_CHANGE, TOP_CLICK, TOP_FOCUS, TOP_INPUT, TOP_KEY_DOWN, TOP_KEY_UP, TOP_SELECTION_CHANGE] + } +}; + +function createAndAccumulateChangeEvent(inst, nativeEvent, target) { + var event = SyntheticEvent.getPooled(eventTypes$1.change, inst, nativeEvent, target); + event.type = 'change'; + // Flag this event loop as needing state restore. + enqueueStateRestore(target); + accumulateTwoPhaseDispatches(event); + return event; +} +/** + * For IE shims + */ +var activeElement = null; +var activeElementInst = null; + +/** + * SECTION: handle `change` event + */ +function shouldUseChangeEvent(elem) { + var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); + return nodeName === 'select' || nodeName === 'input' && elem.type === 'file'; +} + +function manualDispatchChangeEvent(nativeEvent) { + var event = createAndAccumulateChangeEvent(activeElementInst, nativeEvent, getEventTarget(nativeEvent)); + + // If change and propertychange bubbled, we'd just bind to it like all the + // other events and have it go through ReactBrowserEventEmitter. Since it + // doesn't, we manually listen for the events and so we have to enqueue and + // process the abstract event manually. + // + // Batching is necessary here in order to ensure that all event handlers run + // before the next rerender (including event handlers attached to ancestor + // elements instead of directly on the input). Without this, controlled + // components don't work properly in conjunction with event bubbling because + // the component is rerendered and the value reverted before all the event + // handlers can run. See https://github.com/facebook/react/issues/708. + batchedUpdates(runEventInBatch, event); +} + +function runEventInBatch(event) { + runEventsInBatch(event); +} + +function getInstIfValueChanged(targetInst) { + var targetNode = getNodeFromInstance$1(targetInst); + if (updateValueIfChanged(targetNode)) { + return targetInst; + } +} + +function getTargetInstForChangeEvent(topLevelType, targetInst) { + if (topLevelType === TOP_CHANGE) { + return targetInst; + } +} + +/** + * SECTION: handle `input` event + */ +var isInputEventSupported = false; +if (canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events. + isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9); +} + +/** + * (For IE <=9) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ +function startWatchingForValueChange(target, targetInst) { + activeElement = target; + activeElementInst = targetInst; + activeElement.attachEvent('onpropertychange', handlePropertyChange); +} + +/** + * (For IE <=9) Removes the event listeners from the currently-tracked element, + * if any exists. + */ +function stopWatchingForValueChange() { + if (!activeElement) { + return; + } + activeElement.detachEvent('onpropertychange', handlePropertyChange); + activeElement = null; + activeElementInst = null; +} + +/** + * (For IE <=9) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== 'value') { + return; + } + if (getInstIfValueChanged(activeElementInst)) { + manualDispatchChangeEvent(nativeEvent); + } +} + +function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) { + if (topLevelType === TOP_FOCUS) { + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(target, targetInst); + } else if (topLevelType === TOP_BLUR) { + stopWatchingForValueChange(); + } +} + +// For IE8 and IE9. +function getTargetInstForInputEventPolyfill(topLevelType, targetInst) { + if (topLevelType === TOP_SELECTION_CHANGE || topLevelType === TOP_KEY_UP || topLevelType === TOP_KEY_DOWN) { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + return getInstIfValueChanged(activeElementInst); + } +} + +/** + * SECTION: handle `click` event + */ +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + var nodeName = elem.nodeName; + return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio'); +} + +function getTargetInstForClickEvent(topLevelType, targetInst) { + if (topLevelType === TOP_CLICK) { + return getInstIfValueChanged(targetInst); + } +} + +function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) { + if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) { + return getInstIfValueChanged(targetInst); + } +} + +function handleControlledInputBlur(node) { + var state = node._wrapperState; + + if (!state || !state.controlled || node.type !== 'number') { + return; + } + + if (!disableInputAttributeSyncing) { + // If controlled, assign the value attribute to the current value on blur + setDefaultValue(node, 'number', node.value); + } +} + +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - select + */ +var ChangeEventPlugin = { + eventTypes: eventTypes$1, + + _isInputEventSupported: isInputEventSupported, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; + + var getTargetInstFunc = void 0, + handleEventFunc = void 0; + if (shouldUseChangeEvent(targetNode)) { + getTargetInstFunc = getTargetInstForChangeEvent; + } else if (isTextInputElement(targetNode)) { + if (isInputEventSupported) { + getTargetInstFunc = getTargetInstForInputOrChangeEvent; + } else { + getTargetInstFunc = getTargetInstForInputEventPolyfill; + handleEventFunc = handleEventsForInputEventPolyfill; + } + } else if (shouldUseClickEvent(targetNode)) { + getTargetInstFunc = getTargetInstForClickEvent; + } + + if (getTargetInstFunc) { + var inst = getTargetInstFunc(topLevelType, targetInst); + if (inst) { + var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget); + return event; + } + } + + if (handleEventFunc) { + handleEventFunc(topLevelType, targetNode, targetInst); + } + + // When blurring, set the value attribute for number inputs + if (topLevelType === TOP_BLUR) { + handleControlledInputBlur(targetNode); + } + } +}; + +/** + * Module that is injectable into `EventPluginHub`, that specifies a + * deterministic ordering of `EventPlugin`s. A convenient way to reason about + * plugins, without having to package every one of them. This is better than + * having plugins be ordered in the same order that they are injected because + * that ordering would be influenced by the packaging order. + * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that + * preventing default on events is convenient in `SimpleEventPlugin` handlers. + */ +var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin']; + +var SyntheticUIEvent = SyntheticEvent.extend({ + view: null, + detail: null +}); + +var modifierKeyToProp = { + Alt: 'altKey', + Control: 'ctrlKey', + Meta: 'metaKey', + Shift: 'shiftKey' +}; + +// Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support +// getModifierState. If getModifierState is not supported, we map it to a set of +// modifier keys exposed by the event. In this case, Lock-keys are not supported. +/** + * Translation from modifier key to the associated property in the event. + * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers + */ + +function modifierStateGetter(keyArg) { + var syntheticEvent = this; + var nativeEvent = syntheticEvent.nativeEvent; + if (nativeEvent.getModifierState) { + return nativeEvent.getModifierState(keyArg); + } + var keyProp = modifierKeyToProp[keyArg]; + return keyProp ? !!nativeEvent[keyProp] : false; +} + +function getEventModifierState(nativeEvent) { + return modifierStateGetter; +} + +var previousScreenX = 0; +var previousScreenY = 0; +// Use flags to signal movementX/Y has already been set +var isMovementXSet = false; +var isMovementYSet = false; + +/** + * @interface MouseEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var SyntheticMouseEvent = SyntheticUIEvent.extend({ + screenX: null, + screenY: null, + clientX: null, + clientY: null, + pageX: null, + pageY: null, + ctrlKey: null, + shiftKey: null, + altKey: null, + metaKey: null, + getModifierState: getEventModifierState, + button: null, + buttons: null, + relatedTarget: function (event) { + return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement); + }, + movementX: function (event) { + if ('movementX' in event) { + return event.movementX; + } + + var screenX = previousScreenX; + previousScreenX = event.screenX; + + if (!isMovementXSet) { + isMovementXSet = true; + return 0; + } + + return event.type === 'mousemove' ? event.screenX - screenX : 0; + }, + movementY: function (event) { + if ('movementY' in event) { + return event.movementY; + } + + var screenY = previousScreenY; + previousScreenY = event.screenY; + + if (!isMovementYSet) { + isMovementYSet = true; + return 0; + } + + return event.type === 'mousemove' ? event.screenY - screenY : 0; + } +}); + +/** + * @interface PointerEvent + * @see http://www.w3.org/TR/pointerevents/ + */ +var SyntheticPointerEvent = SyntheticMouseEvent.extend({ + pointerId: null, + width: null, + height: null, + pressure: null, + tangentialPressure: null, + tiltX: null, + tiltY: null, + twist: null, + pointerType: null, + isPrimary: null +}); + +var eventTypes$2 = { + mouseEnter: { + registrationName: 'onMouseEnter', + dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] + }, + mouseLeave: { + registrationName: 'onMouseLeave', + dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER] + }, + pointerEnter: { + registrationName: 'onPointerEnter', + dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] + }, + pointerLeave: { + registrationName: 'onPointerLeave', + dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER] + } +}; + +var EnterLeaveEventPlugin = { + eventTypes: eventTypes$2, + + /** + * For almost every interaction we care about, there will be both a top-level + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that + * we do not extract duplicate events. However, moving the mouse into the + * browser from outside will not fire a `mouseout` event. In this case, we use + * the `mouseover` top-level event. + */ + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var isOverEvent = topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER; + var isOutEvent = topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT; + + if (isOverEvent && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { + return null; + } + + if (!isOutEvent && !isOverEvent) { + // Must not be a mouse or pointer in or out - ignoring. + return null; + } + + var win = void 0; + if (nativeEventTarget.window === nativeEventTarget) { + // `nativeEventTarget` is probably a window object. + win = nativeEventTarget; + } else { + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. + var doc = nativeEventTarget.ownerDocument; + if (doc) { + win = doc.defaultView || doc.parentWindow; + } else { + win = window; + } + } + + var from = void 0; + var to = void 0; + if (isOutEvent) { + from = targetInst; + var related = nativeEvent.relatedTarget || nativeEvent.toElement; + to = related ? getClosestInstanceFromNode(related) : null; + } else { + // Moving to a node from outside the window. + from = null; + to = targetInst; + } + + if (from === to) { + // Nothing pertains to our managed components. + return null; + } + + var eventInterface = void 0, + leaveEventType = void 0, + enterEventType = void 0, + eventTypePrefix = void 0; + + if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) { + eventInterface = SyntheticMouseEvent; + leaveEventType = eventTypes$2.mouseLeave; + enterEventType = eventTypes$2.mouseEnter; + eventTypePrefix = 'mouse'; + } else if (topLevelType === TOP_POINTER_OUT || topLevelType === TOP_POINTER_OVER) { + eventInterface = SyntheticPointerEvent; + leaveEventType = eventTypes$2.pointerLeave; + enterEventType = eventTypes$2.pointerEnter; + eventTypePrefix = 'pointer'; + } + + var fromNode = from == null ? win : getNodeFromInstance$1(from); + var toNode = to == null ? win : getNodeFromInstance$1(to); + + var leave = eventInterface.getPooled(leaveEventType, from, nativeEvent, nativeEventTarget); + leave.type = eventTypePrefix + 'leave'; + leave.target = fromNode; + leave.relatedTarget = toNode; + + var enter = eventInterface.getPooled(enterEventType, to, nativeEvent, nativeEventTarget); + enter.type = eventTypePrefix + 'enter'; + enter.target = toNode; + enter.relatedTarget = fromNode; + + accumulateEnterLeaveDispatches(leave, enter, from, to); + + return [leave, enter]; + } +}; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare + ; +} + +var hasOwnProperty$1 = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if (!hasOwnProperty$1.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { + return false; + } + } + + return true; +} + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + + +function get(key) { + return key._reactInternalFiber; +} + +function has(key) { + return key._reactInternalFiber !== undefined; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */0; +var PerformedWork = /* */1; + +// You can change the rest (and add more). +var Placement = /* */2; +var Update = /* */4; +var PlacementAndUpdate = /* */6; +var Deletion = /* */8; +var ContentReset = /* */16; +var Callback = /* */32; +var DidCapture = /* */64; +var Ref = /* */128; +var Snapshot = /* */256; +var Passive = /* */512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */932; + +// Union of all host effects +var HostEffectMask = /* */1023; + +var Incomplete = /* */1024; +var ShouldCapture = /* */2048; + +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + { + var owner = ReactCurrentOwner$1.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender ? warningWithoutStack$1(false, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber.type) || 'A component') : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + !(isFiberMountedImpl(fiber) === MOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + !(state !== UNMOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + var parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) { + // We're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + invariant(false, 'Unable to find node on an unmounted component.'); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + !didFindChild ? invariant(false, 'Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.') : void 0; + } + } + + !(a.alternate === b) ? invariant(false, 'Return fibers should always be each others\' alternates. This error is likely caused by a bug in React. Please file an issue.') : void 0; + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + !(a.tag === HostRoot) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0; + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +function findCurrentHostFiberWithNoPortals(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child && node.tag !== HostPortal) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +function addEventBubbleListener(element, eventType, listener) { + element.addEventListener(eventType, listener, false); +} + +function addEventCaptureListener(element, eventType, listener) { + element.addEventListener(eventType, listener, true); +} + +/** + * @interface Event + * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface + * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent + */ +var SyntheticAnimationEvent = SyntheticEvent.extend({ + animationName: null, + elapsedTime: null, + pseudoElement: null +}); + +/** + * @interface Event + * @see http://www.w3.org/TR/clipboard-apis/ + */ +var SyntheticClipboardEvent = SyntheticEvent.extend({ + clipboardData: function (event) { + return 'clipboardData' in event ? event.clipboardData : window.clipboardData; + } +}); + +/** + * @interface FocusEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var SyntheticFocusEvent = SyntheticUIEvent.extend({ + relatedTarget: null +}); + +/** + * `charCode` represents the actual "character code" and is safe to use with + * `String.fromCharCode`. As such, only keys that correspond to printable + * characters produce a valid `charCode`, the only exception to this is Enter. + * The Tab-key is considered non-printable and does not have a `charCode`, + * presumably because it does not produce a tab-character in browsers. + * + * @param {object} nativeEvent Native browser event. + * @return {number} Normalized `charCode` property. + */ +function getEventCharCode(nativeEvent) { + var charCode = void 0; + var keyCode = nativeEvent.keyCode; + + if ('charCode' in nativeEvent) { + charCode = nativeEvent.charCode; + + // FF does not set `charCode` for the Enter-key, check against `keyCode`. + if (charCode === 0 && keyCode === 13) { + charCode = 13; + } + } else { + // IE8 does not implement `charCode`, but `keyCode` has the correct value. + charCode = keyCode; + } + + // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) + // report Enter as charCode 10 when ctrl is pressed. + if (charCode === 10) { + charCode = 13; + } + + // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. + // Must not discard the (non-)printable Enter-key. + if (charCode >= 32 || charCode === 13) { + return charCode; + } + + return 0; +} + +/** + * Normalization of deprecated HTML5 `key` values + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ +var normalizeKey = { + Esc: 'Escape', + Spacebar: ' ', + Left: 'ArrowLeft', + Up: 'ArrowUp', + Right: 'ArrowRight', + Down: 'ArrowDown', + Del: 'Delete', + Win: 'OS', + Menu: 'ContextMenu', + Apps: 'ContextMenu', + Scroll: 'ScrollLock', + MozPrintableKey: 'Unidentified' +}; + +/** + * Translation from legacy `keyCode` to HTML5 `key` + * Only special keys supported, all others depend on keyboard layout or browser + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ +var translateToKey = { + '8': 'Backspace', + '9': 'Tab', + '12': 'Clear', + '13': 'Enter', + '16': 'Shift', + '17': 'Control', + '18': 'Alt', + '19': 'Pause', + '20': 'CapsLock', + '27': 'Escape', + '32': ' ', + '33': 'PageUp', + '34': 'PageDown', + '35': 'End', + '36': 'Home', + '37': 'ArrowLeft', + '38': 'ArrowUp', + '39': 'ArrowRight', + '40': 'ArrowDown', + '45': 'Insert', + '46': 'Delete', + '112': 'F1', + '113': 'F2', + '114': 'F3', + '115': 'F4', + '116': 'F5', + '117': 'F6', + '118': 'F7', + '119': 'F8', + '120': 'F9', + '121': 'F10', + '122': 'F11', + '123': 'F12', + '144': 'NumLock', + '145': 'ScrollLock', + '224': 'Meta' +}; + +/** + * @param {object} nativeEvent Native browser event. + * @return {string} Normalized `key` property. + */ +function getEventKey(nativeEvent) { + if (nativeEvent.key) { + // Normalize inconsistent values reported by browsers due to + // implementations of a working draft specification. + + // FireFox implements `key` but returns `MozPrintableKey` for all + // printable characters (normalized to `Unidentified`), ignore it. + var key = normalizeKey[nativeEvent.key] || nativeEvent.key; + if (key !== 'Unidentified') { + return key; + } + } + + // Browser does not implement `key`, polyfill as much of it as we can. + if (nativeEvent.type === 'keypress') { + var charCode = getEventCharCode(nativeEvent); + + // The enter-key is technically both printable and non-printable and can + // thus be captured by `keypress`, no other non-printable key should. + return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); + } + if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { + // While user keyboard layout determines the actual meaning of each + // `keyCode` value, almost all function keys have a universal value. + return translateToKey[nativeEvent.keyCode] || 'Unidentified'; + } + return ''; +} + +/** + * @interface KeyboardEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var SyntheticKeyboardEvent = SyntheticUIEvent.extend({ + key: getEventKey, + location: null, + ctrlKey: null, + shiftKey: null, + altKey: null, + metaKey: null, + repeat: null, + locale: null, + getModifierState: getEventModifierState, + // Legacy Interface + charCode: function (event) { + // `charCode` is the result of a KeyPress event and represents the value of + // the actual printable character. + + // KeyPress is deprecated, but its replacement is not yet final and not + // implemented in any major browser. Only KeyPress has charCode. + if (event.type === 'keypress') { + return getEventCharCode(event); + } + return 0; + }, + keyCode: function (event) { + // `keyCode` is the result of a KeyDown/Up event and represents the value of + // physical keyboard key. + + // The actual meaning of the value depends on the users' keyboard layout + // which cannot be detected. Assuming that it is a US keyboard layout + // provides a surprisingly accurate mapping for US and European users. + // Due to this, it is left to the user to implement at this time. + if (event.type === 'keydown' || event.type === 'keyup') { + return event.keyCode; + } + return 0; + }, + which: function (event) { + // `which` is an alias for either `keyCode` or `charCode` depending on the + // type of the event. + if (event.type === 'keypress') { + return getEventCharCode(event); + } + if (event.type === 'keydown' || event.type === 'keyup') { + return event.keyCode; + } + return 0; + } +}); + +/** + * @interface DragEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var SyntheticDragEvent = SyntheticMouseEvent.extend({ + dataTransfer: null +}); + +/** + * @interface TouchEvent + * @see http://www.w3.org/TR/touch-events/ + */ +var SyntheticTouchEvent = SyntheticUIEvent.extend({ + touches: null, + targetTouches: null, + changedTouches: null, + altKey: null, + metaKey: null, + ctrlKey: null, + shiftKey: null, + getModifierState: getEventModifierState +}); + +/** + * @interface Event + * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- + * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent + */ +var SyntheticTransitionEvent = SyntheticEvent.extend({ + propertyName: null, + elapsedTime: null, + pseudoElement: null +}); + +/** + * @interface WheelEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var SyntheticWheelEvent = SyntheticMouseEvent.extend({ + deltaX: function (event) { + return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). + 'wheelDeltaX' in event ? -event.wheelDeltaX : 0; + }, + deltaY: function (event) { + return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). + 'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). + 'wheelDelta' in event ? -event.wheelDelta : 0; + }, + + deltaZ: null, + + // Browsers without "deltaMode" is reporting in raw wheel delta where one + // notch on the scroll is always +/- 120, roughly equivalent to pixels. + // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or + // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. + deltaMode: null +}); + +/** + * Turns + * ['abort', ...] + * into + * eventTypes = { + * 'abort': { + * phasedRegistrationNames: { + * bubbled: 'onAbort', + * captured: 'onAbortCapture', + * }, + * dependencies: [TOP_ABORT], + * }, + * ... + * }; + * topLevelEventsToDispatchConfig = new Map([ + * [TOP_ABORT, { sameConfig }], + * ]); + */ + +var interactiveEventTypeNames = [[TOP_BLUR, 'blur'], [TOP_CANCEL, 'cancel'], [TOP_CLICK, 'click'], [TOP_CLOSE, 'close'], [TOP_CONTEXT_MENU, 'contextMenu'], [TOP_COPY, 'copy'], [TOP_CUT, 'cut'], [TOP_AUX_CLICK, 'auxClick'], [TOP_DOUBLE_CLICK, 'doubleClick'], [TOP_DRAG_END, 'dragEnd'], [TOP_DRAG_START, 'dragStart'], [TOP_DROP, 'drop'], [TOP_FOCUS, 'focus'], [TOP_INPUT, 'input'], [TOP_INVALID, 'invalid'], [TOP_KEY_DOWN, 'keyDown'], [TOP_KEY_PRESS, 'keyPress'], [TOP_KEY_UP, 'keyUp'], [TOP_MOUSE_DOWN, 'mouseDown'], [TOP_MOUSE_UP, 'mouseUp'], [TOP_PASTE, 'paste'], [TOP_PAUSE, 'pause'], [TOP_PLAY, 'play'], [TOP_POINTER_CANCEL, 'pointerCancel'], [TOP_POINTER_DOWN, 'pointerDown'], [TOP_POINTER_UP, 'pointerUp'], [TOP_RATE_CHANGE, 'rateChange'], [TOP_RESET, 'reset'], [TOP_SEEKED, 'seeked'], [TOP_SUBMIT, 'submit'], [TOP_TOUCH_CANCEL, 'touchCancel'], [TOP_TOUCH_END, 'touchEnd'], [TOP_TOUCH_START, 'touchStart'], [TOP_VOLUME_CHANGE, 'volumeChange']]; +var nonInteractiveEventTypeNames = [[TOP_ABORT, 'abort'], [TOP_ANIMATION_END, 'animationEnd'], [TOP_ANIMATION_ITERATION, 'animationIteration'], [TOP_ANIMATION_START, 'animationStart'], [TOP_CAN_PLAY, 'canPlay'], [TOP_CAN_PLAY_THROUGH, 'canPlayThrough'], [TOP_DRAG, 'drag'], [TOP_DRAG_ENTER, 'dragEnter'], [TOP_DRAG_EXIT, 'dragExit'], [TOP_DRAG_LEAVE, 'dragLeave'], [TOP_DRAG_OVER, 'dragOver'], [TOP_DURATION_CHANGE, 'durationChange'], [TOP_EMPTIED, 'emptied'], [TOP_ENCRYPTED, 'encrypted'], [TOP_ENDED, 'ended'], [TOP_ERROR, 'error'], [TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture'], [TOP_LOAD, 'load'], [TOP_LOADED_DATA, 'loadedData'], [TOP_LOADED_METADATA, 'loadedMetadata'], [TOP_LOAD_START, 'loadStart'], [TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture'], [TOP_MOUSE_MOVE, 'mouseMove'], [TOP_MOUSE_OUT, 'mouseOut'], [TOP_MOUSE_OVER, 'mouseOver'], [TOP_PLAYING, 'playing'], [TOP_POINTER_MOVE, 'pointerMove'], [TOP_POINTER_OUT, 'pointerOut'], [TOP_POINTER_OVER, 'pointerOver'], [TOP_PROGRESS, 'progress'], [TOP_SCROLL, 'scroll'], [TOP_SEEKING, 'seeking'], [TOP_STALLED, 'stalled'], [TOP_SUSPEND, 'suspend'], [TOP_TIME_UPDATE, 'timeUpdate'], [TOP_TOGGLE, 'toggle'], [TOP_TOUCH_MOVE, 'touchMove'], [TOP_TRANSITION_END, 'transitionEnd'], [TOP_WAITING, 'waiting'], [TOP_WHEEL, 'wheel']]; + +var eventTypes$4 = {}; +var topLevelEventsToDispatchConfig = {}; + +function addEventTypeNameToConfig(_ref, isInteractive) { + var topEvent = _ref[0], + event = _ref[1]; + + var capitalizedEvent = event[0].toUpperCase() + event.slice(1); + var onEvent = 'on' + capitalizedEvent; + + var type = { + phasedRegistrationNames: { + bubbled: onEvent, + captured: onEvent + 'Capture' + }, + dependencies: [topEvent], + isInteractive: isInteractive + }; + eventTypes$4[event] = type; + topLevelEventsToDispatchConfig[topEvent] = type; +} + +interactiveEventTypeNames.forEach(function (eventTuple) { + addEventTypeNameToConfig(eventTuple, true); +}); +nonInteractiveEventTypeNames.forEach(function (eventTuple) { + addEventTypeNameToConfig(eventTuple, false); +}); + +// Only used in DEV for exhaustiveness validation. +var knownHTMLTopLevelTypes = [TOP_ABORT, TOP_CANCEL, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_CLOSE, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_INPUT, TOP_INVALID, TOP_LOAD, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_RESET, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUBMIT, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_TOGGLE, TOP_VOLUME_CHANGE, TOP_WAITING]; + +var SimpleEventPlugin = { + eventTypes: eventTypes$4, + + isInteractiveTopLevelEventType: function (topLevelType) { + var config = topLevelEventsToDispatchConfig[topLevelType]; + return config !== undefined && config.isInteractive === true; + }, + + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; + if (!dispatchConfig) { + return null; + } + var EventConstructor = void 0; + switch (topLevelType) { + case TOP_KEY_PRESS: + // Firefox creates a keypress event for function keys too. This removes + // the unwanted keypress events. Enter is however both printable and + // non-printable. One would expect Tab to be as well (but it isn't). + if (getEventCharCode(nativeEvent) === 0) { + return null; + } + /* falls through */ + case TOP_KEY_DOWN: + case TOP_KEY_UP: + EventConstructor = SyntheticKeyboardEvent; + break; + case TOP_BLUR: + case TOP_FOCUS: + EventConstructor = SyntheticFocusEvent; + break; + case TOP_CLICK: + // Firefox creates a click event on right mouse clicks. This removes the + // unwanted click events. + if (nativeEvent.button === 2) { + return null; + } + /* falls through */ + case TOP_AUX_CLICK: + case TOP_DOUBLE_CLICK: + case TOP_MOUSE_DOWN: + case TOP_MOUSE_MOVE: + case TOP_MOUSE_UP: + // TODO: Disabled elements should not respond to mouse events + /* falls through */ + case TOP_MOUSE_OUT: + case TOP_MOUSE_OVER: + case TOP_CONTEXT_MENU: + EventConstructor = SyntheticMouseEvent; + break; + case TOP_DRAG: + case TOP_DRAG_END: + case TOP_DRAG_ENTER: + case TOP_DRAG_EXIT: + case TOP_DRAG_LEAVE: + case TOP_DRAG_OVER: + case TOP_DRAG_START: + case TOP_DROP: + EventConstructor = SyntheticDragEvent; + break; + case TOP_TOUCH_CANCEL: + case TOP_TOUCH_END: + case TOP_TOUCH_MOVE: + case TOP_TOUCH_START: + EventConstructor = SyntheticTouchEvent; + break; + case TOP_ANIMATION_END: + case TOP_ANIMATION_ITERATION: + case TOP_ANIMATION_START: + EventConstructor = SyntheticAnimationEvent; + break; + case TOP_TRANSITION_END: + EventConstructor = SyntheticTransitionEvent; + break; + case TOP_SCROLL: + EventConstructor = SyntheticUIEvent; + break; + case TOP_WHEEL: + EventConstructor = SyntheticWheelEvent; + break; + case TOP_COPY: + case TOP_CUT: + case TOP_PASTE: + EventConstructor = SyntheticClipboardEvent; + break; + case TOP_GOT_POINTER_CAPTURE: + case TOP_LOST_POINTER_CAPTURE: + case TOP_POINTER_CANCEL: + case TOP_POINTER_DOWN: + case TOP_POINTER_MOVE: + case TOP_POINTER_OUT: + case TOP_POINTER_OVER: + case TOP_POINTER_UP: + EventConstructor = SyntheticPointerEvent; + break; + default: + { + if (knownHTMLTopLevelTypes.indexOf(topLevelType) === -1) { + warningWithoutStack$1(false, 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' + 'is likely caused by a bug in React. Please file an issue.', topLevelType); + } + } + // HTML Events + // @see http://www.w3.org/TR/html5/index.html#events-0 + EventConstructor = SyntheticEvent; + break; + } + var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget); + accumulateTwoPhaseDispatches(event); + return event; + } +}; + +var isInteractiveTopLevelEventType = SimpleEventPlugin.isInteractiveTopLevelEventType; + + +var CALLBACK_BOOKKEEPING_POOL_SIZE = 10; +var callbackBookkeepingPool = []; + +/** + * Find the deepest React component completely containing the root of the + * passed-in instance (for use when entire React trees are nested within each + * other). If React trees are not nested, returns null. + */ +function findRootContainerNode(inst) { + // TODO: It may be a good idea to cache this to prevent unnecessary DOM + // traversal, but caching is difficult to do correctly without using a + // mutation observer to listen for all DOM changes. + while (inst.return) { + inst = inst.return; + } + if (inst.tag !== HostRoot) { + // This can happen if we're in a detached tree. + return null; + } + return inst.stateNode.containerInfo; +} + +// Used to store ancestor hierarchy in top level callback +function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) { + if (callbackBookkeepingPool.length) { + var instance = callbackBookkeepingPool.pop(); + instance.topLevelType = topLevelType; + instance.nativeEvent = nativeEvent; + instance.targetInst = targetInst; + return instance; + } + return { + topLevelType: topLevelType, + nativeEvent: nativeEvent, + targetInst: targetInst, + ancestors: [] + }; +} + +function releaseTopLevelCallbackBookKeeping(instance) { + instance.topLevelType = null; + instance.nativeEvent = null; + instance.targetInst = null; + instance.ancestors.length = 0; + if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) { + callbackBookkeepingPool.push(instance); + } +} + +function handleTopLevel(bookKeeping) { + var targetInst = bookKeeping.targetInst; + + // Loop through the hierarchy, in case there's any nested components. + // It's important that we build the array of ancestors before calling any + // event handlers, because event handlers can modify the DOM, leading to + // inconsistencies with ReactMount's node cache. See #1105. + var ancestor = targetInst; + do { + if (!ancestor) { + bookKeeping.ancestors.push(ancestor); + break; + } + var root = findRootContainerNode(ancestor); + if (!root) { + break; + } + bookKeeping.ancestors.push(ancestor); + ancestor = getClosestInstanceFromNode(root); + } while (ancestor); + + for (var i = 0; i < bookKeeping.ancestors.length; i++) { + targetInst = bookKeeping.ancestors[i]; + runExtractedEventsInBatch(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent)); + } +} + +// TODO: can we stop exporting these? +var _enabled = true; + +function setEnabled(enabled) { + _enabled = !!enabled; +} + +function isEnabled() { + return _enabled; +} + +/** + * Traps top-level events by using event bubbling. + * + * @param {number} topLevelType Number from `TopLevelEventTypes`. + * @param {object} element Element on which to attach listener. + * @return {?object} An object with a remove function which will forcefully + * remove the listener. + * @internal + */ +function trapBubbledEvent(topLevelType, element) { + if (!element) { + return null; + } + var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent; + + addEventBubbleListener(element, getRawEventName(topLevelType), + // Check if interactive and wrap in interactiveUpdates + dispatch.bind(null, topLevelType)); +} + +/** + * Traps a top-level event by using event capturing. + * + * @param {number} topLevelType Number from `TopLevelEventTypes`. + * @param {object} element Element on which to attach listener. + * @return {?object} An object with a remove function which will forcefully + * remove the listener. + * @internal + */ +function trapCapturedEvent(topLevelType, element) { + if (!element) { + return null; + } + var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent; + + addEventCaptureListener(element, getRawEventName(topLevelType), + // Check if interactive and wrap in interactiveUpdates + dispatch.bind(null, topLevelType)); +} + +function dispatchInteractiveEvent(topLevelType, nativeEvent) { + interactiveUpdates(dispatchEvent, topLevelType, nativeEvent); +} + +function dispatchEvent(topLevelType, nativeEvent) { + if (!_enabled) { + return; + } + + var nativeEventTarget = getEventTarget(nativeEvent); + var targetInst = getClosestInstanceFromNode(nativeEventTarget); + if (targetInst !== null && typeof targetInst.tag === 'number' && !isFiberMounted(targetInst)) { + // If we get an event (ex: img onload) before committing that + // component's mount, ignore it for now (that is, treat it as if it was an + // event on a non-React tree). We might also consider queueing events and + // dispatching them after the mount. + targetInst = null; + } + + var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst); + + try { + // Event queue being processed in the same cycle allows + // `preventDefault`. + batchedUpdates(handleTopLevel, bookKeeping); + } finally { + releaseTopLevelCallbackBookKeeping(bookKeeping); + } +} + +/** + * Summary of `ReactBrowserEventEmitter` event handling: + * + * - Top-level delegation is used to trap most native browser events. This + * may only occur in the main thread and is the responsibility of + * ReactDOMEventListener, which is injected and can therefore support + * pluggable event sources. This is the only work that occurs in the main + * thread. + * + * - We normalize and de-duplicate events to account for browser quirks. This + * may be done in the worker thread. + * + * - Forward these native events (with the associated top-level type used to + * trap it) to `EventPluginHub`, which in turn will ask plugins if they want + * to extract any synthetic events. + * + * - The `EventPluginHub` will then process each event by annotating them with + * "dispatches", a sequence of listeners and IDs that care about that event. + * + * - The `EventPluginHub` then dispatches the events. + * + * Overview of React and the event system: + * + * +------------+ . + * | DOM | . + * +------------+ . + * | . + * v . + * +------------+ . + * | ReactEvent | . + * | Listener | . + * +------------+ . +-----------+ + * | . +--------+|SimpleEvent| + * | . | |Plugin | + * +-----|------+ . v +-----------+ + * | | | . +--------------+ +------------+ + * | +-----------.--->|EventPluginHub| | Event | + * | | . | | +-----------+ | Propagators| + * | ReactEvent | . | | |TapEvent | |------------| + * | Emitter | . | |<---+|Plugin | |other plugin| + * | | . | | +-----------+ | utilities | + * | +-----------.--->| | +------------+ + * | | | . +--------------+ + * +-----|------+ . ^ +-----------+ + * | . | |Enter/Leave| + * + . +-------+|Plugin | + * +-------------+ . +-----------+ + * | application | . + * |-------------| . + * | | . + * | | . + * +-------------+ . + * . + * React Core . General Purpose Event Plugin System + */ + +var alreadyListeningTo = {}; +var reactTopListenersCounter = 0; + +/** + * To ensure no conflicts with other potential React instances on the page + */ +var topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2); + +function getListeningForDocument(mountAt) { + // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` + // directly. + if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { + mountAt[topListenersIDKey] = reactTopListenersCounter++; + alreadyListeningTo[mountAt[topListenersIDKey]] = {}; + } + return alreadyListeningTo[mountAt[topListenersIDKey]]; +} + +/** + * We listen for bubbled touch events on the document object. + * + * Firefox v8.01 (and possibly others) exhibited strange behavior when + * mounting `onmousemove` events at some node that was not the document + * element. The symptoms were that if your mouse is not moving over something + * contained within that mount point (for example on the background) the + * top-level listeners for `onmousemove` won't be called. However, if you + * register the `mousemove` on the document object, then it will of course + * catch all `mousemove`s. This along with iOS quirks, justifies restricting + * top-level listeners to the document object only, at least for these + * movement types of events and possibly all events. + * + * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html + * + * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but + * they bubble to document. + * + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {object} mountAt Container where to mount the listener + */ +function listenTo(registrationName, mountAt) { + var isListening = getListeningForDocument(mountAt); + var dependencies = registrationNameDependencies[registrationName]; + + for (var i = 0; i < dependencies.length; i++) { + var dependency = dependencies[i]; + if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { + switch (dependency) { + case TOP_SCROLL: + trapCapturedEvent(TOP_SCROLL, mountAt); + break; + case TOP_FOCUS: + case TOP_BLUR: + trapCapturedEvent(TOP_FOCUS, mountAt); + trapCapturedEvent(TOP_BLUR, mountAt); + // We set the flag for a single dependency later in this function, + // but this ensures we mark both as attached rather than just one. + isListening[TOP_BLUR] = true; + isListening[TOP_FOCUS] = true; + break; + case TOP_CANCEL: + case TOP_CLOSE: + if (isEventSupported(getRawEventName(dependency))) { + trapCapturedEvent(dependency, mountAt); + } + break; + case TOP_INVALID: + case TOP_SUBMIT: + case TOP_RESET: + // We listen to them on the target DOM elements. + // Some of them bubble so we don't want them to fire twice. + break; + default: + // By default, listen on the top level to all non-media events. + // Media events don't bubble so adding the listener wouldn't do anything. + var isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1; + if (!isMediaEvent) { + trapBubbledEvent(dependency, mountAt); + } + break; + } + isListening[dependency] = true; + } + } +} + +function isListeningToAllDependencies(registrationName, mountAt) { + var isListening = getListeningForDocument(mountAt); + var dependencies = registrationNameDependencies[registrationName]; + for (var i = 0; i < dependencies.length; i++) { + var dependency = dependencies[i]; + if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { + return false; + } + } + return true; +} + +function getActiveElement(doc) { + doc = doc || (typeof document !== 'undefined' ? document : undefined); + if (typeof doc === 'undefined') { + return null; + } + try { + return doc.activeElement || doc.body; + } catch (e) { + return doc.body; + } +} + +/** + * Given any node return the first leaf node without children. + * + * @param {DOMElement|DOMTextNode} node + * @return {DOMElement|DOMTextNode} + */ +function getLeafNode(node) { + while (node && node.firstChild) { + node = node.firstChild; + } + return node; +} + +/** + * Get the next sibling within a container. This will walk up the + * DOM if a node's siblings have been exhausted. + * + * @param {DOMElement|DOMTextNode} node + * @return {?DOMElement|DOMTextNode} + */ +function getSiblingNode(node) { + while (node) { + if (node.nextSibling) { + return node.nextSibling; + } + node = node.parentNode; + } +} + +/** + * Get object describing the nodes which contain characters at offset. + * + * @param {DOMElement|DOMTextNode} root + * @param {number} offset + * @return {?object} + */ +function getNodeForCharacterOffset(root, offset) { + var node = getLeafNode(root); + var nodeStart = 0; + var nodeEnd = 0; + + while (node) { + if (node.nodeType === TEXT_NODE) { + nodeEnd = nodeStart + node.textContent.length; + + if (nodeStart <= offset && nodeEnd >= offset) { + return { + node: node, + offset: offset - nodeStart + }; + } + + nodeStart = nodeEnd; + } + + node = getLeafNode(getSiblingNode(node)); + } +} + +/** + * @param {DOMElement} outerNode + * @return {?object} + */ +function getOffsets(outerNode) { + var ownerDocument = outerNode.ownerDocument; + + var win = ownerDocument && ownerDocument.defaultView || window; + var selection = win.getSelection && win.getSelection(); + + if (!selection || selection.rangeCount === 0) { + return null; + } + + var anchorNode = selection.anchorNode, + anchorOffset = selection.anchorOffset, + focusNode = selection.focusNode, + focusOffset = selection.focusOffset; + + // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the + // up/down buttons on an . Anonymous divs do not seem to + // expose properties, triggering a "Permission denied error" if any of its + // properties are accessed. The only seemingly possible way to avoid erroring + // is to access a property that typically works for non-anonymous divs and + // catch any error that may otherwise arise. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 + + try { + /* eslint-disable no-unused-expressions */ + anchorNode.nodeType; + focusNode.nodeType; + /* eslint-enable no-unused-expressions */ + } catch (e) { + return null; + } + + return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset); +} + +/** + * Returns {start, end} where `start` is the character/codepoint index of + * (anchorNode, anchorOffset) within the textContent of `outerNode`, and + * `end` is the index of (focusNode, focusOffset). + * + * Returns null if you pass in garbage input but we should probably just crash. + * + * Exported only for testing. + */ +function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset) { + var length = 0; + var start = -1; + var end = -1; + var indexWithinAnchor = 0; + var indexWithinFocus = 0; + var node = outerNode; + var parentNode = null; + + outer: while (true) { + var next = null; + + while (true) { + if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) { + start = length + anchorOffset; + } + if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) { + end = length + focusOffset; + } + + if (node.nodeType === TEXT_NODE) { + length += node.nodeValue.length; + } + + if ((next = node.firstChild) === null) { + break; + } + // Moving from `node` to its first child `next`. + parentNode = node; + node = next; + } + + while (true) { + if (node === outerNode) { + // If `outerNode` has children, this is always the second time visiting + // it. If it has no children, this is still the first loop, and the only + // valid selection is anchorNode and focusNode both equal to this node + // and both offsets 0, in which case we will have handled above. + break outer; + } + if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { + start = length; + } + if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { + end = length; + } + if ((next = node.nextSibling) !== null) { + break; + } + node = parentNode; + parentNode = node.parentNode; + } + + // Moving from `node` to its next sibling `next`. + node = next; + } + + if (start === -1 || end === -1) { + // This should never happen. (Would happen if the anchor/focus nodes aren't + // actually inside the passed-in node.) + return null; + } + + return { + start: start, + end: end + }; +} + +/** + * In modern non-IE browsers, we can support both forward and backward + * selections. + * + * Note: IE10+ supports the Selection object, but it does not support + * the `extend` method, which means that even in modern IE, it's not possible + * to programmatically create a backward selection. Thus, for all IE + * versions, we use the old IE API to create our selections. + * + * @param {DOMElement|DOMTextNode} node + * @param {object} offsets + */ +function setOffsets(node, offsets) { + var doc = node.ownerDocument || document; + var win = doc && doc.defaultView || window; + + // Edge fails with "Object expected" in some scenarios. + // (For instance: TinyMCE editor used in a list component that supports pasting to add more, + // fails when pasting 100+ items) + if (!win.getSelection) { + return; + } + + var selection = win.getSelection(); + var length = node.textContent.length; + var start = Math.min(offsets.start, length); + var end = offsets.end === undefined ? start : Math.min(offsets.end, length); + + // IE 11 uses modern selection, but doesn't support the extend method. + // Flip backward selections, so we can set with a single range. + if (!selection.extend && start > end) { + var temp = end; + end = start; + start = temp; + } + + var startMarker = getNodeForCharacterOffset(node, start); + var endMarker = getNodeForCharacterOffset(node, end); + + if (startMarker && endMarker) { + if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) { + return; + } + var range = doc.createRange(); + range.setStart(startMarker.node, startMarker.offset); + selection.removeAllRanges(); + + if (start > end) { + selection.addRange(range); + selection.extend(endMarker.node, endMarker.offset); + } else { + range.setEnd(endMarker.node, endMarker.offset); + selection.addRange(range); + } + } +} + +function isTextNode(node) { + return node && node.nodeType === TEXT_NODE; +} + +function containsNode(outerNode, innerNode) { + if (!outerNode || !innerNode) { + return false; + } else if (outerNode === innerNode) { + return true; + } else if (isTextNode(outerNode)) { + return false; + } else if (isTextNode(innerNode)) { + return containsNode(outerNode, innerNode.parentNode); + } else if ('contains' in outerNode) { + return outerNode.contains(innerNode); + } else if (outerNode.compareDocumentPosition) { + return !!(outerNode.compareDocumentPosition(innerNode) & 16); + } else { + return false; + } +} + +function isInDocument(node) { + return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node); +} + +function isSameOriginFrame(iframe) { + try { + // Accessing the contentDocument of a HTMLIframeElement can cause the browser + // to throw, e.g. if it has a cross-origin src attribute. + // Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g: + // iframe.contentDocument.defaultView; + // A safety way is to access one of the cross origin properties: Window or Location + // Which might result in "SecurityError" DOM Exception and it is compatible to Safari. + // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl + + return typeof iframe.contentWindow.location.href === 'string'; + } catch (err) { + return false; + } +} + +function getActiveElementDeep() { + var win = window; + var element = getActiveElement(); + while (element instanceof win.HTMLIFrameElement) { + if (isSameOriginFrame(element)) { + win = element.contentWindow; + } else { + return element; + } + element = getActiveElement(win.document); + } + return element; +} + +/** + * @ReactInputSelection: React input selection module. Based on Selection.js, + * but modified to be suitable for react and has a couple of bug fixes (doesn't + * assume buttons have range selections allowed). + * Input selection module for React. + */ + +/** + * @hasSelectionCapabilities: we get the element types that support selection + * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart` + * and `selectionEnd` rows. + */ +function hasSelectionCapabilities(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + return nodeName && (nodeName === 'input' && (elem.type === 'text' || elem.type === 'search' || elem.type === 'tel' || elem.type === 'url' || elem.type === 'password') || nodeName === 'textarea' || elem.contentEditable === 'true'); +} + +function getSelectionInformation() { + var focusedElem = getActiveElementDeep(); + return { + focusedElem: focusedElem, + selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection$1(focusedElem) : null + }; +} + +/** + * @restoreSelection: If any selection information was potentially lost, + * restore it. This is useful when performing operations that could remove dom + * nodes and place them back in, resulting in focus being lost. + */ +function restoreSelection(priorSelectionInformation) { + var curFocusedElem = getActiveElementDeep(); + var priorFocusedElem = priorSelectionInformation.focusedElem; + var priorSelectionRange = priorSelectionInformation.selectionRange; + if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { + if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) { + setSelection(priorFocusedElem, priorSelectionRange); + } + + // Focusing a node can change the scroll position, which is undesirable + var ancestors = []; + var ancestor = priorFocusedElem; + while (ancestor = ancestor.parentNode) { + if (ancestor.nodeType === ELEMENT_NODE) { + ancestors.push({ + element: ancestor, + left: ancestor.scrollLeft, + top: ancestor.scrollTop + }); + } + } + + if (typeof priorFocusedElem.focus === 'function') { + priorFocusedElem.focus(); + } + + for (var i = 0; i < ancestors.length; i++) { + var info = ancestors[i]; + info.element.scrollLeft = info.left; + info.element.scrollTop = info.top; + } + } +} + +/** + * @getSelection: Gets the selection bounds of a focused textarea, input or + * contentEditable node. + * -@input: Look up selection bounds of this input + * -@return {start: selectionStart, end: selectionEnd} + */ +function getSelection$1(input) { + var selection = void 0; + + if ('selectionStart' in input) { + // Modern browser with input or textarea. + selection = { + start: input.selectionStart, + end: input.selectionEnd + }; + } else { + // Content editable or old IE textarea. + selection = getOffsets(input); + } + + return selection || { start: 0, end: 0 }; +} + +/** + * @setSelection: Sets the selection bounds of a textarea or input and focuses + * the input. + * -@input Set selection bounds of this input or textarea + * -@offsets Object of same form that is returned from get* + */ +function setSelection(input, offsets) { + var start = offsets.start, + end = offsets.end; + + if (end === undefined) { + end = start; + } + + if ('selectionStart' in input) { + input.selectionStart = start; + input.selectionEnd = Math.min(end, input.value.length); + } else { + setOffsets(input, offsets); + } +} + +var skipSelectionChangeEvent = canUseDOM && 'documentMode' in document && document.documentMode <= 11; + +var eventTypes$3 = { + select: { + phasedRegistrationNames: { + bubbled: 'onSelect', + captured: 'onSelectCapture' + }, + dependencies: [TOP_BLUR, TOP_CONTEXT_MENU, TOP_DRAG_END, TOP_FOCUS, TOP_KEY_DOWN, TOP_KEY_UP, TOP_MOUSE_DOWN, TOP_MOUSE_UP, TOP_SELECTION_CHANGE] + } +}; + +var activeElement$1 = null; +var activeElementInst$1 = null; +var lastSelection = null; +var mouseDown = false; + +/** + * Get an object which is a unique representation of the current selection. + * + * The return value will not be consistent across nodes or browsers, but + * two identical selections on the same node will return identical objects. + * + * @param {DOMElement} node + * @return {object} + */ +function getSelection(node) { + if ('selectionStart' in node && hasSelectionCapabilities(node)) { + return { + start: node.selectionStart, + end: node.selectionEnd + }; + } else { + var win = node.ownerDocument && node.ownerDocument.defaultView || window; + var selection = win.getSelection(); + return { + anchorNode: selection.anchorNode, + anchorOffset: selection.anchorOffset, + focusNode: selection.focusNode, + focusOffset: selection.focusOffset + }; + } +} + +/** + * Get document associated with the event target. + * + * @param {object} nativeEventTarget + * @return {Document} + */ +function getEventTargetDocument(eventTarget) { + return eventTarget.window === eventTarget ? eventTarget.document : eventTarget.nodeType === DOCUMENT_NODE ? eventTarget : eventTarget.ownerDocument; +} + +/** + * Poll selection to see whether it's changed. + * + * @param {object} nativeEvent + * @param {object} nativeEventTarget + * @return {?SyntheticEvent} + */ +function constructSelectEvent(nativeEvent, nativeEventTarget) { + // Ensure we have the right element, and that the user is not dragging a + // selection (this matches native `select` event behavior). In HTML5, select + // fires only on input and textarea thus if there's no focused element we + // won't dispatch. + var doc = getEventTargetDocument(nativeEventTarget); + + if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement(doc)) { + return null; + } + + // Only fire when selection has actually changed. + var currentSelection = getSelection(activeElement$1); + if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { + lastSelection = currentSelection; + + var syntheticEvent = SyntheticEvent.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget); + + syntheticEvent.type = 'select'; + syntheticEvent.target = activeElement$1; + + accumulateTwoPhaseDispatches(syntheticEvent); + + return syntheticEvent; + } + + return null; +} + +/** + * This plugin creates an `onSelect` event that normalizes select events + * across form elements. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - contentEditable + * + * This differs from native browser implementations in the following ways: + * - Fires on contentEditable fields as well as inputs. + * - Fires for collapsed selection. + * - Fires after user input. + */ +var SelectEventPlugin = { + eventTypes: eventTypes$3, + + extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) { + var doc = getEventTargetDocument(nativeEventTarget); + // Track whether all listeners exists for this plugin. If none exist, we do + // not extract events. See #3639. + if (!doc || !isListeningToAllDependencies('onSelect', doc)) { + return null; + } + + var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window; + + switch (topLevelType) { + // Track the input node that has focus. + case TOP_FOCUS: + if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') { + activeElement$1 = targetNode; + activeElementInst$1 = targetInst; + lastSelection = null; + } + break; + case TOP_BLUR: + activeElement$1 = null; + activeElementInst$1 = null; + lastSelection = null; + break; + // Don't fire the event while the user is dragging. This matches the + // semantics of the native select event. + case TOP_MOUSE_DOWN: + mouseDown = true; + break; + case TOP_CONTEXT_MENU: + case TOP_MOUSE_UP: + case TOP_DRAG_END: + mouseDown = false; + return constructSelectEvent(nativeEvent, nativeEventTarget); + // Chrome and IE fire non-standard event when selection is changed (and + // sometimes when it hasn't). IE's event fires out of order with respect + // to key and input events on deletion, so we discard it. + // + // Firefox doesn't support selectionchange, so check selection status + // after each key entry. The selection changes after keydown and before + // keyup, but we check on keydown as well in the case of holding down a + // key, when multiple keydown events are fired but only one keyup is. + // This is also our approach for IE handling, for the reason above. + case TOP_SELECTION_CHANGE: + if (skipSelectionChangeEvent) { + break; + } + // falls through + case TOP_KEY_DOWN: + case TOP_KEY_UP: + return constructSelectEvent(nativeEvent, nativeEventTarget); + } + + return null; + } +}; + +/** + * Inject modules for resolving DOM hierarchy and plugin ordering. + */ +injection.injectEventPluginOrder(DOMEventPluginOrder); +setComponentTree(getFiberCurrentPropsFromNode$1, getInstanceFromNode$1, getNodeFromInstance$1); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + SimpleEventPlugin: SimpleEventPlugin, + EnterLeaveEventPlugin: EnterLeaveEventPlugin, + ChangeEventPlugin: ChangeEventPlugin, + SelectEventPlugin: SelectEventPlugin, + BeforeInputEventPlugin: BeforeInputEventPlugin +}); + +var didWarnSelectedSetOnOption = false; +var didWarnInvalidChild = false; + +function flattenChildren(children) { + var content = ''; + + // Flatten children. We'll warn if they are invalid + // during validateProps() which runs for hydration too. + // Note that this would throw on non-element objects. + // Elements are stringified (which is normally irrelevant + // but matters for ). + React.Children.forEach(children, function (child) { + if (child == null) { + return; + } + content += child; + // Note: we don't warn about invalid children here. + // Instead, this is done separately below so that + // it happens during the hydration codepath too. + }); + + return content; +} + +/** + * Implements an